您的位置:首页 > 其它

POJ 1151 Atlantis (线段树+扫描线 求矩形面积并)

2015-05-14 20:08 399 查看
经典扫描线题,算法网上有很详细的,这里简单说一下:

把每个矩形拆成两条竖边,标记每条边是左边的还是右边的,把所有的边按x坐标排序。用一个数组cov标记整个y轴每个部分在多少个矩形中,哪些不是。把浮点数离散化。

然后开始扫描:先把答案加上(全部在矩形中的区间的长度和)×(这条边x坐标和前一条边x坐标之差),代表这两条边之间被覆盖的面积,然后这条边如果是左边,就把所覆盖区间的cov数组+1,是右边就-1.

区间加和查询用线段树实现,但是是一个特殊的线段树。

1.对于区间(l,r),它的子区间是(l,mid)和(mid,r)。

2.不需要lazy数组,因为查询的区间永远只有一个就是最大区间,所以更新某个区间后不需要更新它的子区间。

3.pushup时,如果cov[rt]大于0,长度就是整个区间,否则就是两个子区间长度和(不是0)

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson l,mid,rt<<1
#define rson mid,r,rt<<1|1
using namespace std;
#include <set>
#include <map>

set<double> Rem;
map<double,int> Hash;

double a[1000];
int cov[1000];

int N;
struct line{
	double x,iy1,iy2;
	int y1,y2;
	int c;
}Line[205];

double Y[205];

bool cmp(line a,line b){
	if(a.x==b.x) return a.c<b.c;
	return a.x<b.x;
}

void pushup(int l,int r,int rt){
	if(cov[rt]>0) a[rt]=Y[r]-Y[l];
	else a[rt]=a[rt<<1]+a[rt<<1|1];
}

void update(int l,int r,int rt,int L,int R,int c){
	if(l>=L&&r<=R){
		cov[rt]+=c;
		pushup(l,r,rt);
		return ;
	}
	int mid=(l+r)/2;
	if(mid>L) update(lson,L,R,c);
	if(mid<R) update(rson,L,R,c);
	pushup(l,r,rt);
}

int main(){
	int kase=1;
	while(~scanf("%d",&N)){
		if(!N) break;
		memset(a,0,sizeof(a));
		memset(cov,0,sizeof(cov));
		memset(Y,0,sizeof(Y));
		Rem.clear();
		Hash.clear();
		for(int i=0;i<N;i++){
			double x1,x2,y1,y2;
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			Line[i].x=x1;Line[i].c=1;
			Line[i].iy1=y1;Line[i].iy2=y2;
			Line[i+N].x=x2;Line[i+N].c=-1;
			Line[i+N].iy1=y1;Line[i+N].iy2=y2;
			Rem.insert(y1);Rem.insert(y2);
		}
		set<double>::iterator p;
		int cnt=0;
		for(p=Rem.begin();p!=Rem.end();p++){
			Hash[*p]=++cnt;
			Y[cnt]=*p;
		}
		sort(Line,Line+2*N,cmp);
		for(int i=0;i<N*2;i++){
			Line[i].y1=Hash[Line[i].iy1];
			Line[i].y2=Hash[Line[i].iy2];
		}
		update(1,cnt,1,Line[0].y1,Line[0].y2,Line[0].c);
		double res=0;
		for(int i=1;i<2*N;i++){
			res+=(Line[i].x-Line[i-1].x)*a[1];
			update(1,cnt,1,Line[i].y1,Line[i].y2,Line[i].c);
		}
		printf("Test case #%d\n",kase++);
		printf("Total explored area: %.2f\n\n",res);
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: