Description
Input
Output
Sample Input
2 10 10 20 20 15 15 25 25.5 0
Sample Output
Test case #1
Total explored area: 180.00题意:
求矩形面积的并;
思路:线段树+离散化(为什么要离散化,因为(1)坐标给的范围很大,如果对这 么大的数据用线段树来表示的话,在操作的过程中肯定会超时,而且100个矩阵,最多只有200个点, 线段树中有很多的无效的数据,(2)而且坐标给的还是浮点数,操作麻烦)
步骤:
(1)对所有的矩阵的纵坐标集合排序后进行离散化建树
(2)构建扫描线,如图:
图中红色的竖线代表扫描线,结合程序看,第一次调用Updata(1,line(1))进行更新的时候,最左边的红色的线段的c(覆盖)=1;也就是有效线段,通过这个有效线段求出了图中的黑色区域的面积,然后第二次调用更新函数,此时第二条红色的扫描线段的下半部分(第一条红色线段有标记把扫描线分上下两部分)的c现在为2(因为第一次已经覆盖了一次c就为1了),然后把所有c大于1的线段加起来就为当前的有效线段长度(长度为第二条扫描线长度加上第一条扫描线的下半部分,因为之前为1),求得紫色的部分面积,然后第三次调用更新函数,从新计算几部分线段的c值(注意此时的扫描线段的flag为-1,对c有减的作用,当这条线段的c为0后,就不加这条线段到有效的长度中了),第四次调用扫描线段数因为所有的线段的c都为0了,所以有效长度为0
CODE(有注释)
#include<iostream> #include<algorithm> #include<stdio.h> using namespace std; #define MAXN 205 typedef struct { int l; int r; int c;/*记录有效长度是否被覆盖*/ double cnt,lf,rf;/*有效长度cnt,lf,lr分别表示原图上真正的长度*/ }Node;/*节点*/ Node segtree[3*MAXN];/*开的空间,已经离散化了,所以一般区间开的大小为矩形点总个数的3倍*/ typedef struct { double x; /*垂直以x轴的扫描线与y轴的距离*/ double y1,y2; int flag;/*标记每个矩形左边的扫描线为1,右边的扫描线为-1,便于计算c*/ } Line; Line line[MAXN]; double Y[MAXN];/*便于等一下映射到线段树里面的lf与rf中*/ bool cmp(Line a,Line b) { return a.x<b.x; } void Build_segtree(int t,int l,int r)/*建立线段树*/ { int mid; segtree[t].l=l; segtree[t].r=r; segtree[t].c=segtree[t].cnt=0; segtree[t].lf=Y[l]; segtree[t].rf=Y[r]; if(l+1==r)return; mid=(l+r)/2; Build_segtree(t*2,l,mid); Build_segtree(t*2+1,mid,r); } void compute(int t)/*通过逐步回溯来计算 segtree[t].cnt,一直回溯t==1,然后求出了有效的长度cnt*/ { if(segtree[t].c>0) { segtree[t].cnt=segtree[t].rf-segtree[t].lf; return; } if(segtree[t].l+1==segtree[t].r)segtree[t].cnt=0; else segtree[t].cnt=segtree[t*2].cnt+segtree[t*2+1].cnt; } void Updata(int t,Line cur)/*扫描更新c值,然后就是递归然后回溯计算有效长度*/ { Line temp; if(cur.y1==segtree[t].lf&&cur.y2==segtree[t].rf) { segtree[t].c+=cur.flag; compute(t); return; } if(cur.y2<=segtree[t*2].rf)Updata(t*2,cur); else if(cur.y1>=segtree[t*2+1].lf)Updata(t*2+1,cur); else { temp=cur; temp.y2=segtree[t*2].rf; Updata(t*2,temp); temp=cur; temp.y1=segtree[t*2+1].lf; Updata(t*2+1,temp); } compute(t); } int main() { int i,n,icase=0; int t; double ans; double x1,y1,x2,y2; while(scanf("%d",&n)!=-1&&n) { icase++; t=1; for(i=1;i<=n;i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); line[t].x=x1; line[t].y1=y1; line[t].y2=y2; line[t].flag=1; Y[t]=y1; t++; line[t].x=x2; line[t].y1=y1; line[t].y2=y2; line[t].flag=-1; Y[t]=y2; t++; } sort(line+1,line+t,cmp);/*关于x进行排序,确定扫描线的相对位置*/ sort(Y+1,Y+t);/*对于y排序,便于等一下建树分段时候的映射*/ Build_segtree(1,1,t-1); Updata(1,line[1]); ans=0; for(i=2;i<t;i++) { ans+=segtree[1].cnt*(line[i].x-line[i-1].x);/*把每一段求和相加*/ Updata(1,line[i]); } printf("Test case #%d\nTotal explored area: %.2lf\n\n",icase,ans); } return 0; }