hdu 1255 扫描线+线段树计算矩形面积并

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1255

 

题意:给你n个矩形,要你计算这些矩形被覆盖两次以上部分的面积和。

 

做法:

        刚学的扫描线,留个板子和参考链接,很多地方容易出细节问题。

 

#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1

using namespace std;
const int maxn=1005;
struct seg{
    double l,r,h;
    int v;
}se[maxn*2];

int num[maxn<<3];
double once[maxn<<3],twice[maxn<<3];
bool cmp(seg a,seg b){
    return a.h<b.h;
}
int n,k,m;
double X[maxn*2];
int fin(double x){
    int l=1,r=m;
    while(l<=r){
        int mid=(l+r)/2;
        if(X[mid]==x) return mid;
        if(X[mid]>x) r=mid-1;
        else l=mid+1;
    }
    return -1;
}
void deal(int rt,int l,int r){
    //deal只更新一块区域,上面的是跟着更新的但是不会增加num值
    if(num[rt]) //如果有覆盖,则一次覆盖的就是左右差
        //注意 这里的(] 是为了保证连续区间不会重复加
        once[rt]=X[r+1]-X[l];
    else if (l==r)//如果是叶子结点 那么就是0
        once[rt]=0;
    else
        once[rt]=once[lson]+once[rson];


    if(num[rt]>1)
        twice[rt]=X[r+1]-X[l];
    else if(l==r)
        twice[rt]=0;
    else if(num[rt]==1)
        twice[rt]=once[lson]+once[rson];
    else
        twice[rt]=twice[lson]+twice[rson];
}
void update(int ql,int qr,int l,int r,int v,int rt){
    if(l>=ql&&r<=qr){
        num[rt]+=v;
        deal(rt,l,r);
        return ;
    }
    int mid=(l+r)/2;
    if(ql<=mid) update(ql,qr,l,mid,v,lson);
    if(qr>mid) update(ql,qr,mid+1,r,v,rson);
    deal(rt,l,r);
}
int main(){
    int t;
    cin>>t;
    while(t--){
        scanf("%d",&n);
        k=1;
        for(int i=1;i<=n;i++,k+=2){
            double x1,x2,y1,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            X[k]=x1,X[k+1]=x2;
            se[k].l=x1,se[k].r=x2,se[k].h=y1,se[k].v=1;
            se[k+1].l=x1,se[k+1].r=x2,se[k+1].h=y2,se[k+1].v=-1;
        }
        k--;
        sort(se+1,se+1+k,cmp);
        sort(X+1,X+1+k);
        X[0]=-1;
        m=0;
        for(int i=1;i<=k;i++){
            if(X[i]!=X[i-1]) X[++m]=X[i];
        }
        memset(num,0,sizeof(num));
        memset(once,0,sizeof(once));
        memset(twice,0,sizeof(twice));
        double ans=0;
        for(int i=1;i<k;i++){
            int l=fin(se[i].l);
            int r=fin(se[i].r)-1;
            update(l,r,1,m,se[i].v,1);
            ans=(ans+twice[1]*(se[i+1].h-se[i].h));
            //printf("i=%d ans=%.2f\n",i,ans);
        }
        printf("%.2f\n",ans);
    }

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值