Description
Input
The input file is terminated by a line containing a single 0. Don't process it.
Output
Output a blank line after each test case.
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;
}