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

/*
在这里将一个一个的矩形分隔成两条平行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)>>1
double 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值