//根据几篇的代码修改了,自己好看懂点,haha
#include <stdio.h>#include <string.h>#include <math.h>#include <algorithm>using namespace std;struct node{ int l,r,cov; double len;//cov是覆盖情况,len表示覆盖的长度}e[222*4];struct line{//平行于y轴的线段 double x,up,down; int flag;//1表示矩阵左边,-1是右边}f[222];int cmp(line a,line b){ return a.x<b.x;}double y[222];void build(int a,int b,int c)//建线段树{ e[c].l=a; e[c].r=b; e[c].len=0; e[c].cov=0; if(a==b) return; int mid=(a+b)/2; build(a,mid,2*c); build(mid+1,b,2*c+1);}void update(int a,int b,int c,int flag)//修改覆盖情况cov,以及计算,{ if(a==e[c].l&&b==e[c].r) { if(flag==1)//cov不可能出现负数,因而可以直接判断 { e[c].cov++; e[c].len=y[b+1]-y[a]; } else { e[c].cov--; if(e[c].cov==0) { if(e[c].l==e[c].r)//叶结点 e[c].len=0; else e[c].len=e[2*c].len+e[2*c+1].len; } } return; } int mid=(e[c].l+e[c].r)/2; if(b<=mid) update(a,b,2*c,flag); else if(a>mid) update(a,b,2*c+1,flag); else { update(a,mid,2*c,flag); update(mid+1,b,2*c+1,flag); } if(e[c].cov==0) e[c].len=e[2*c].len+e[2*c+1].len;}int binary(double a[],int l,int r,double x) //二分查找x,并返回为序号 O(logN){ int mid; while(l<=r) { mid = (l+r)>>1; if(x < a[mid]) r = mid -1; else { if(x > a[mid]) l = mid +1; else return mid; } }}int main(){ int n,tt=0; while(scanf("%d",&n)!=EOF) { if(n==0) break; int i,j,k,t=0; double x1,y1,x2,y2; for(i=0;i<n;i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); y[t]=y1;f[t].x=x1;f[t].up=y2;f[t].down=y1;f[t++].flag=1; y[t]=y2;f[t].x=x2;f[t].up=y2;f[t].down=y1;f[t++].flag=-1; } sort(y,y+t);//将y1和y2的值离散化成0到t-1的值 sort(f,f+t,cmp);//用结构体数组f记录每条平行于y轴的线段 build(0,t-1,1); double ans=0; for(i=0;i<t;i++) { if(i!=0) ans+=(f[i].x-f[i-1].x)*e[1].len; int l=binary(y,0,t-1,f[i].down);//二分查找离散化对应值 int r=binary(y,0,t-1,f[i].up)-1;//线段长度,由于线段树处理的是点,所以每点表示y[i+1]-y[i]段,所以线段最后点要-1 update(l,r,1,f[i].flag); } printf("Test case #%d\nTotal explored area: %.2lf\n\n",++tt,ans); } return 0;}/*举例:数据210 10 20 2015 15 25 25.50无限延长所有平行于Y轴的线,可得到总面积就是三个矩形((10,10),(15,20)),((15,10)(20,25.5)),((20,15),(25,25.5))面积之和离散化各点的纵坐标并排序,得到y[0]=10,y[1]=15,y[2]=20,y[3]=25.5;构建0到3的线段树,其中cov是覆盖情况。从横坐标小的开始枚举所有平行于y轴的线段,如果是矩形左边就cov+1,否则cov-1这样我们可以知道cov不为0的就是上述三个矩形的宽,长就是两个两个横坐标的差*//*转载原理:【题意】:线段树经典应用,求矩形并的面积【分析】:第一道矩形几何题,主要是练习线段树来的 求矩形的并,由于矩形的位置可以多变,因此矩形的面积一下子不好求这个时候,可以采用“分割”的思想,即把整块的矩形面积分割成几个小矩形的面积,然后求和就行了这里我们可以这样做,把每个矩形投影到 y 坐标轴上来然后我们可以枚举矩形的 x 坐标,然后检测当前相邻 x 坐标上 y 方向的合法长度,两种相乘就是面积 然后关键就是如何用线段树来维护那个 “合法长度”可以这样来搞线段树的节点这样定义struct node { int left,right,cov; double len; }cov 表示当前节点区间是否被覆盖,len 是当前区间的合法长度 然后我们通过“扫描线”的方法来进行扫描枚举 x 的竖边,矩形的左边那条竖边就是入边,右边那条就是出边了然后把所有这些竖边按照 x 坐标递增排序,每次进行插入操作由于坐标不一定为整数,因此需要进行离散化处理每次插入时如果当前区间被完全覆盖,那么就要对 cov 域进行更新入边 +1 出边 -1更新完毕后判断当前节点的 cov 域是否大于 0如果大于 0,那么当前节点的 len 域就是节点所覆盖的区间否则如果是叶子节点,则 len=0如果内部节点,则 len=左右儿子的 len 之和转自---------http://blog.sina.com.cn/s/blog_88705ca20100ufl0.html*/