P - Atlantis (线段树+扫描线)
InputThe input file consists of several test cases. Each test case starts with a line containing a single integer n (1<=n<=100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0<=x1<x2<=100000;0<=y1<y2<=100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.
The input file is terminated by a line containing a single 0. Don’t process it.OutputFor each test case, your program should output one section. The first line of each section must be “Test case #k”, where k is the number of the test case (starting with 1). The second one must be “Total explored area: a”, where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.
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
题解:扫描线常规操作,如果不会先看大神的讲解再来:https://blog.csdn.net/xianpingping/article/details/83032798
#include<bits/stdc++.h> using namespace std; const int maxn=205; double x[maxn]; struct node { double l,r,h; int d; bool operator < (const node &a)const//按纵坐标从小到大排序 { return h<a.h; } }line[maxn]; int cnt[maxn<<2];//cnt[rt]表示该节点的覆盖次数,只要不为0就是被覆盖过 double sum[maxn<<2];//线段树sum[rt]中每一个节点都是一个区间,sum[rt]表示该节点区间中的总有效覆盖长度 double area; void pushup(int l,int r,int rt) { if(cnt[rt])//如果该节点(就是一个区间)全部被覆盖,那么sum就是这个区间的长度了~ sum[rt]=x[r+1]-x[l];//x的下标是点,对于线段树的一个区间要进行右边下标+1再减去左边 else //否则要进行左右儿子的加和,因为不连续啊~ sum[rt]=sum[rt*2]+sum[rt*2+1]; } void update(int L,int R,int v,int l,int r,int rt)//在L,R区间覆盖次数加上v,即如果v为1就加1,为-1就减1 { if(L<=l&&R>=r) { cnt[rt]+=v; pushup(l,r,rt);//改变了cnt数组后要重新pushup return ; } int mid=(l+r)/2;//下面常规操作~ if(L<=mid) update(L,R,v,l,mid,rt*2); if(R>=mid+1) update(L,R,v,mid+1,r,rt*2+1); pushup(l,r,rt); } int main() { int t,k=1; while(cin>>t&&t) { memset(cnt,0,sizeof(cnt));//初始化全部为0 memset(sum,0,sizeof(sum)); area=0; //求得面积 int n=0,m=0;//x数组得最大元素个数,line数组得最大元素个数 for(int i=1;i<=t;i++)//记录信息 { double x1,y1,x2,y2; cin>>x1>>y1>>x2>>y2; x[++n]=x1; x[++n]=x2; line[++m]=(node){x1,x2,y1,1}; line[++m]=(node){x1,x2,y2,-1}; } sort(x+1,x+1+n);//对x数组从小打大排序 sort(line+1,line+1+m);//对line扫描线数组按高度(即y)从小到大排序 int r=unique(x+1,x+1+n)-x-1;//r个不同的x将一条线段分成r-1个小区间,这也是后面查询总区长度是1到r-1和R--的原因 for(int i=1;i<m;i++)//这里是对扫描线进行扫描~,扫描m-1次即可 { int L=lower_bound(x+1,x+r+1,line[i].l)-x; int R=lower_bound(x+1,x+r+1,line[i].r)-x; R--;//每一个节点是一个区间,这里是将点转化为区间的操作 update(L,R,line[i].d,1,r-1,1); area+=sum[1]*(line[i+1].h-line[i].h);//用总有效长度乘上两条扫描线之间的距离即得到该块面积 } printf("Test case #%d\nTotal explored area: %.2f\n\n",k++,area); } return 0; }