HDU 1255 覆盖的面积 (求矩形面积的交)
覆盖的面积
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Description
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.
Input
输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.
注意:本题的输入数据较多,推荐使用scanf读入数据.
注意:本题的输入数据较多,推荐使用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
题意:求矩形面积的交。
分析:就是矩形面积并的一个升级版,在求并时,重复多少次我们并没有管,现在要叫我们求至少相交2次的面积,为此可以在结构体中增加一个变量ss,表示覆盖2次及以上的区间长度,s表示覆盖一次的长度,改变的就只有计算长度的那个函数,如何计算ss:
1.cnt>1 : 说明该区间被覆盖两次或以上,那么长度就可以直接计算,就是该区间的长度
剩下的情况就是cnt=1或cnt=0
2.先看叶子节点,因为是叶子没有孩子了,所以被覆盖两次货以上的长度就是0(无论cnt=1或cnt=0都是0,因为是叶子。。。)
3.不是叶子节点 ,且cnt=1.注意这里,cnt=1确切的意义是什么,应该是,可以确定,这个区间被完全覆盖了1次,而有没有被完全覆盖两次或以上则不知道无法确定,那么怎么怎么办了,只要加上t[lch].s + t[rch].s 即,看看左右孩子区间被覆盖了一次或以上的长度,那么叠加在双亲上就是双亲被覆盖两次或以上的长度
3.不是叶子节点,且cnt=0,确切的意义应该是不完全不知道被覆盖的情况(不知道有没有被覆盖,被覆盖了几次,长度是多少都不知道),这种情况,只能由其左右孩子的信息所得
t[lch].ss + t[rch].ss , 即直接将左右孩子给覆盖了两次或以上的长度加起来。
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 1100; struct Node { int l,r; double cnt;//该节点的覆盖情况 double s,ss; }segTree[2*MAXN*4]; struct Segment { double l,r,h; int f; }ss[MAXN*2]; double pos[MAXN*2]; bool cmp(const Segment& aa,const Segment& bb) { return aa.h<bb.h; } void build(int id,int l,int r) { segTree[id].l=l; segTree[id].r=r; segTree[id].cnt=0; segTree[id].s=0; segTree[id].ss=0; if(l==r) return; int mid=(l+r)/2; build(id*2,l,mid); build(id*2+1,mid+1,r); } void calen(int id) { if(segTree[id].cnt) segTree[id].s=pos[segTree[id].r+1]-pos[segTree[id].l]; else if(segTree[id].l==segTree[id].r) segTree[id].s=0; else segTree[id].s=segTree[id*2].s+segTree[id*2+1].s; if(segTree[id].cnt>1) segTree[id].ss=pos[segTree[id].r+1]-pos[segTree[id].l]; else if(segTree[id].l==segTree[id].r) segTree[id].ss=0; else if(segTree[id].cnt==1) segTree[id].ss=segTree[id*2].s+segTree[id*2+1].s; else segTree[id].ss=segTree[id*2].ss+segTree[id*2+1].ss; } void update(int id,int l,int r,int val) { if(segTree[id].l==l&&segTree[id].r==r) { segTree[id].cnt+=val; calen(id); return; } int mid=(segTree[id].l+segTree[id].r)/2; if(l>mid) update(id*2+1,l,r,val); else if(r<=mid) update(id*2,l,r,val); else { update(id*2,l,mid,val); update(id*2+1,mid+1,r,val); } calen(id); } int main() { int T; int n; double x1,y1,x2,y2; scanf("%d",&T); while(T--) { int t=1; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); ss[t].l=x1,ss[t].r=x2,ss[t].h=y1,ss[t].f=1,pos[t]=x1,t++; ss[t].l=x1,ss[t].r=x2,ss[t].h=y2,ss[t].f=-1,pos[t]=x2,t++; } sort(ss+1,ss+t,cmp); sort(pos+1,pos+t); //for(int i=1; i<t; i++) printf("%.2lf %.2lf %.2lf\n",ss[i].l,ss[i].r,ss[i].h); int m=2; for(int i=2;i<t;i++) if(pos[i]!=pos[i-1]) pos[m++]=pos[i]; build(1,1,m-1); double ans=0; for(int i=1;i<t;i++) { int l=lower_bound(pos+1,pos+m,ss[i].l)-pos; int r=lower_bound(pos+1,pos+m,ss[i].r)-pos-1; //cout<<l<<" "<<r<<endl; update(1,l,r,ss[i].f); ans+=(ss[i+1].h-ss[i].h)*segTree[1].ss; } printf("%.2lf\n",ans); } return 0; }