hdu 1542 Atlantis(线段树,扫描线)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542

题意:n个矩阵,给出每个矩阵的左下和右上两个点的坐标,求出所有矩形总的覆盖面积。


扫描线问题,因为坐标是浮点型,那就必须把坐标离散化,我这直接上map了。

再来就是求这个面积的方式了:我这是向y轴映射,那么就保存每一条竖线,包扩该条竖线的x坐标,上下两个y坐标,还有用lr保存这条竖线是左边(1)那条还是右边(-1)那条,然后将所有的竖边按x从小到大排序,再一条一条地插入。看图:


先插入第一条竖边A1A2,再查询整棵数被覆盖的长度dy(即求出y坐标之差),这时候dy*(下一条边的x-插入这的条边的x)就等于第一部分的面积,以此类推。

插入A1A2可以求第一部分面积

插入B1B2可以求第二部分面积

插入C1C2可以求第三部分面积

最后一条不用插入

还有用1和-1标识左右边在这里也能看出来,当插入C1C2的时候,-1和插入A1A2时的1相抵消,表示这个区间不再覆盖,就避免了后面再计算时错误判断dy的值。

代码:

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#define MAXN 1050
using namespace std;
struct ele
{
	double x,yu,yd;
	int lr;
	bool operator < (ele t) const
	{
		return x<t.x;
	}
}a[MAXN*2];
struct node
{
	int l,r;
	int cover;
}t[MAXN*5];
double yy[MAXN*2];
void construct(int l,int r,int p)
{
	t[p].l=l,t[p].r=r,t[p].cover=0;
	if(r-l<=1) return ;
	int m=(l+r)>>1;
	construct(l,m,p*2);
	construct(m,r,p*2+1);
}
void modify(int l,int r,int val,int p)
{
	if(t[p].l==l&&t[p].r==r)
	{
		t[p].cover+=val;
		return ;
	}
	int m=(t[p].l+t[p].r)>>1;
	if(r<=m)
		modify(l,r,val,p*2);
	else if(l>=m)
		modify(l,r,val,p*2+1);
	else
	{
		modify(l,m,val,p*2);
		modify(m,r,val,p*2+1);
	}
}
void query(double &ans,int p)
{
	if(t[p].cover)
	{
		ans+=yy[t[p].r]-yy[t[p].l];
		return ;
	}
	else if(t[p].r-t[p].l>=1)
	{
		t[p*2].cover+=t[p].cover,t[p*2+1].cover+=t[p].cover;
		query(ans,p*2);
		query(ans,p*2+1);
		t[p*2].cover-=t[p].cover,t[p*2+1].cover-=t[p].cover;
	}
}
int main()
{
	int n,i,j,cas=1;
	double x1,x2,y1,y2;
	map<double,int> hash;
	while(scanf("%d",&n)&&n)
	{
		for(i=1,j=1;i<=n;i++,j+=2)
		{
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			a[j].x=x1,a[j].yd=y1,a[j].yu=y2;
			a[j].lr=1;
			a[j+1].x=x2,a[j+1].yd=y1,a[j+1].yu=y2;
			a[j+1].lr=-1;
			yy[j]=y1,yy[j+1]=y2;
		}
		sort(a+1,a+1+n*2);
		sort(yy+1,yy+1+2*n);
		int up=unique(yy+1,yy+1+2*n)-yy-1;
		for(i=1;i<=up;i++)
			hash[yy[i]]=i;
		double res=0,dy;
		construct(1,up,1);
		for(i=1;i<2*n;i++)
		{
			dy=0;
			modify(hash[a[i].yd],hash[a[i].yu],a[i].lr,1);
			query(dy,1);
			res+=dy*(a[i+1].x-a[i].x);
		}
		printf("Test case #%d\n",cas++);
		printf("Total explored area: %.2lf\n\n",res);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值