Description
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.
Input
The input 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.
Output
For 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
题意:给出n个矩形的左下角和右上角的坐标,求出所有矩形面积的并。
分析:
参考https://blog.csdn.net/riba2534/article/details/76851233
给出若干相互重叠矩形
假设一根线从下往上开始扫描
如图所示,所要求的面积即为各颜色矩形面积之和,扫描线扫过的距离为各矩形的高,利用线段树维护矩形的长度。对每个矩形的上下边分别标记为-1和1,扫描线遇到标记为1的边则将线段树内被覆盖的区间结点记录的矩形个数cnt+1,否则cnt-1。线段树内区间结点cnt>0表示该区间被覆盖可直接得到长度,否则计算其左右子区间内长度之和即为该区间内总长度。由于本题中线段树结点对应的是区间不是点,所以计算的时候边的右端点横坐标序号r要减1才为线段树对应区间结点的序号。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=220;
double X[maxn];//横坐标集合 ,用于离散化
struct Edge{
double l,r,y;//边的左端横坐标、右端横坐标、纵坐标
int val; //边标记值,1或-1
Edge(){ }
Edge(double l,double r,double y,int val):
l(l),r(r),y(y),val(val) {}
bool operator<(const Edge &other)const
{
return y<other.y;
}
}edge[maxn]; //横边的集合
struct node{
int cnt; //完全覆盖该区间的矩形个数
double len;//区间内扫描到的矩形长度
}tree[maxn<<2];
void push_up(int root,int l,int r)
{//更新区间内扫描到的矩形长度
if(tree[root].cnt)
{//被某矩形覆盖则长度为区间长度
tree[root].len=X[r+1]-X[l];//r+1为右端点序号
}
else if(l==r) //点,长度为0
tree[root].len=0;
else
{//长度为左右两个子区间内长度之和
tree[root].len=tree[root<<1].len+tree[root<<1|1].len;
}
}
void update(int root,int l,int r,int L,int R,int val)
{
if(L<=l&&R>=r)
{//该区间被完全覆盖则更新标记的值
tree[root].cnt+=val;
push_up(root,l,r);
return;
}
int mid=(l+r)/2;
if(L<=mid) update(root<<1,l,mid,L,R,val);
if(R>mid) update(root<<1|1,mid+1,r,L,R,val);
push_up(root,l,r);
}
int main()
{
int n,num,k=1;
double ans;
while(~scanf("%d",&n)&&n)
{
num=0;
memset(tree,0,sizeof(tree));
for(int i=0;i<n;i++)
{
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
edge[num]=Edge(x1,x2,y1,1);//下边标记1
X[num++]=x1;
edge[num]=Edge(x1,x2,y2,-1);//上边标记-1
X[num++]=x2;
}
sort(X,X+num); //对所有横坐标排序
sort(edge,edge+num);//对所有横边按纵坐标排序
num=unique(X,X+num)-X;//去重
ans=0;
for(int i=0;i<n*2;i++)
{
int x1=lower_bound(X,X+num,edge[i].l)-X;
int x2=lower_bound(X,X+num,edge[i].r)-X-1;//右端点序号减一得到对应区间的序号
update(1,0,num-1,x1,x2,edge[i].val);
ans+=tree[1].len*(edge[i+1].y-edge[i].y); //长度*高
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n",k++,ans);
}
return 0;
}