HDU 1255 覆盖的面积 (矩形面积交)

点击打开链接


Problem Description
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.


 

Input
输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.

注意:本题的输入数据较多,推荐使用scanf读入数据.
 

Output
对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数.
 

Sample Input
 
 
2 5 1 1 4 2 1 3 3 7 2 1.5 5 4.5 3.5 1.25 7.5 4 6 3 10 7 3 0 0 1 1 1 0 2 1 2 0 3 1
 

Sample Output
 
 
7.63 0.00

#include<cstdio>
#include<cstring>
#include<algorithm> 
#include<cmath>
#define debug(x) printf("%d***\n",x)
#define ls(o) (o<<1)
#define rs(o) (o<<1|1)
typedef long long ll;
using namespace std;
const int maxn=1010;

struct SEG{
    double l,r,h;
    int tag; 
    SEG(){    }
    SEG(double _l,double _r,double _h,int _tag){
        l=_l,r=_r,h=_h,tag=_tag; 
    }
    bool operator<(const SEG& b)const{
        return h<b.h;
    }
}seg[maxn<<1];

double X[maxn<<1];

struct Tree{
    int l,r;
    double sum1,sum2;//sum1表示当前区间遍历大于等于一次的长度,sum2表示当前区间大于等于两次的长度 
    int cnt;
}tree[maxn<<3];
/*
利用sum1 来保存大于等于一次的长度,我们每次只更新对应的最高区间,也就是能不往下去就不往下去
然后利用sum2=ls(o).sum1+rs(o).sum1;//当前区间是一次,所以只要下面的一次就够了 
*/
void build(int l,int r,int o){
    tree[o].l=l,tree[o].r=r;
    tree[o].cnt=0;
    if(l==r){
        tree[o].sum1=tree[o].sum2=0.0;
        return ;
    } 
    int mid=(l+r)>>1;
    build(l,mid,ls(o));
    build(mid+1,r,rs(o));
    tree[o].sum1=tree[ls(o)].sum1+tree[rs(o)].sum1;
    tree[o].sum2=tree[ls(o)].sum2+tree[rs(o)].sum2;
}

void pushup(int o){//!!! 
    if(tree[o].cnt>=2){
    	tree[o].sum2=tree[o].sum1=X[tree[o].r+1]-X[tree[o].l];
    }
    else if(tree[o].cnt==1){
    	tree[o].sum1=X[tree[o].r+1]-X[tree[o].l];
    	if(tree[o].l==tree[o].r) tree[o].sum2=0.0;
    	else tree[o].sum2=tree[ls(o)].sum1+tree[rs(o)].sum1;
    }
    else {
    	if(tree[o].l==tree[o].r)
        	tree[o].sum1=tree[o].sum2=0.0;
        else{
        	tree[o].sum1=tree[ls(o)].sum1+tree[rs(o)].sum1;
			tree[o].sum2=tree[ls(o)].sum2+tree[rs(o)].sum2; 
        }
    }
}

void update(int l,int r,int v,int o){
	//printf("l:%d r:%d o:%d\n",l,r,o);
    if(l<=tree[o].l&&tree[o].r<=r){
        tree[o].cnt+=v;
	    pushup(o);
        return;
    }
	int mid=(tree[o].l+tree[o].r)>>1;
    if(r<=mid)
        update(l,r,v,ls(o));
    else if(l>mid) 
        update(l,r,v,rs(o));
    else{
        update(l,mid,v,ls(o));
        update(mid+1,r,v,rs(o));
    }
    pushup(o);
}

int main(){
    //freopen("123.txt","r",stdin);
    //freopen("456.txt","w",stdout);
    int q,T;
    scanf("%d",&T);
    while(T--){
    	scanf("%d",&q);
        int n=0,m=0;
        for(int i=1;i<=q;i++){
            double x1,y1,x2,y2;
            scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
            X[++n]=x1;
            seg[++m]=(SEG){x1,x2,y1,1};
            X[++n]=x2;
            seg[++m]=(SEG){x1,x2,y2,-1};
        }
        sort(seg+1,seg+m+1);
        //去重 
		sort(X+1,X+n+1);
        int k=1;
        for(int i=2;i<=n;i++){
            if(X[i]!=X[i-1])
                X[++k]=X[i];
        }
        build(1,k-1,1);
        double ans=0.0;
        for(int i=1;i<m;i++){
            int l=lower_bound(X+1,X+k+1,seg[i].l)-X;
            int r=lower_bound(X+1,X+k+1,seg[i].r)-X;
            update(l,r-1,seg[i].tag,1);
            ans+=tree[1].sum2*(seg[i+1].h-seg[i].h);
           // printf("ans:%.2f ll:%.2f rr:%.2f h1:%.2f h2:%.2f l:%d r:%d sum:%.2f\n",ans,seg[i].l,seg[i].r,seg[i].h,seg[i+1].h,l,r-1,tree[1].sum2);
        }
        printf("%.2f\n",ans);
        
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值