hdu 1542 ,1255 线段树面积并与面积交

来源:互联网 发布:java判断float是否为0 编辑:程序博客网 时间:2024/04/19 10:25
/*在这里将一个一个的矩形分隔成两条平行X轴的线,在下面一条标记为正边,上面一条标记为负边。cnt表示的次节点被覆盖的次数。sum表示区间一次覆盖以上的长度len表示区间二次覆盖以上的长度*/#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;#define maxn 2222#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define mid (l+r)>>1double X[maxn<<2],sum[maxn<<2],len[maxn<<2];int cnt[maxn<<2];struct Seg{        double l,r,h;        int c;        Seg(){};        Seg(double t1,double t2,double t3,int t4) :l(t1),r(t2),h(t3),c(t4){}         bool operator < (Seg& cmp){                return h<cmp.h;        }}seg[maxn<<2];void Pushup(int l,int r,int rt){        if(cnt[rt])                sum[rt] = X[r+1]-X[l];//实际长度时往开区间移        else if(l == r)                sum[rt] = 0;        else                sum[rt] = sum[rt<<1]+sum[rt<<1|1];}void Pushupagain(int l,int r,int rt){        if(cnt[rt]>=2) //如果已经两次以上被覆盖,即为交集                len[rt] = X[r+1] -X[l];        else if(l == r)//叶子节点长度为0                len[rt] = 0;        else if(cnt[rt] == 1)//如果覆盖线段为1,那么等于已经覆盖的左右子树的长度和                len[rt] = sum[rt<<1] +sum[rt<<1|1];        else //否则等于已经覆盖的左右子树长度和。                len[rt] = len[rt<<1] + len[rt<<1|1];}int Bin(double key,int n){        return lower_bound(X,X+n,key)-X;}void Update(int L,int R,int c,int l,int r,int rt){        if(L<=l && r<=R){                cnt[rt]+=c;                Pushup(l,r,rt);                Pushupagain(l,r,rt);                return ;        }        int m=mid;        if(m>=L)                Update(L,R,c,lson);        if(m<R)                Update(L,R,c,rson);        Pushup(l,r,rt);        Pushupagain(l,r,rt);}int main(){        int t,i,j,T;        scanf("%d",&T);        while(T--){                scanf("%d",&t);                double a[4];                int n=0;                for(i=0;i<t;i++){                        for(j=0;j<4;j++)                                scanf("%lf",&a[j]);                        seg[n]=Seg(a[0],a[2],a[1],1);                        X[n++]=a[0];                        seg[n]=Seg(a[0],a[2],a[3],-1);                        X[n++]=a[2];                                        }                sort(seg,seg+n);                sort(X,X+n);                int k=1;                for(i=1;i<n;i++){ //去重离散化                        if(X[i-1]!=X[i])                                X[k++]=X[i];                }                memset(cnt,0,sizeof(cnt));                memset(sum,0,sizeof(sum));                memset(len,0,sizeof(len));                double area=0,sre=0;                for(i=0;i<n-1;i++){                        int l=Bin(seg[i].l,k);                        int r=Bin(seg[i].r,k)-1; //左闭右开区间,取实区时往后移一个                        if(l<=r)                        Update(l,r,seg[i].c,0,k-1,1);                                area+=len[1]*(seg[i+1].h-seg[i].h);                        //sre+=sum[1]*(seg[i+1].h-seg[i].h);                }        //      printf("Test case #%d\nTotal explored area: %.2lf\n\n",++cas,area);                printf("%.2lf\n",area);//area 为面积交,sre为面积并        }        return 0;}