POJ 1151 Atlantis 线段树+离散化+扫描线

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;	
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值