POJ 1151 Atlantis(线段树离散化求面积并)(C++)

题目链接:http://poj.org/problem?id=1151

算是模板题,做这个之前要搞懂离散化。这里,区间最好用[L,R),要不然有些区间无法计算得到。人比较懒,自己去琢磨,不写注释了QAQ。

#include <cstdio>
#include <vector>
#include <memory.h>
#include <algorithm>
#define maxn 110
using namespace std;
struct Line{
	Line(int a,int b,double c,int d):left(a),right(b),y(c),weight(d){}
	Line(){}
	int left,right,weight;
	double y;
	friend bool operator<(Line p,Line q){
		return p.y<q.y;
	}
};
struct Rect{
	double x1,y1,x2,y2;
}Data[maxn];
struct Node{
	int left,right;
	int cover;
}de[8*maxn];
vector<double>Map;
vector<Line>line;
int n;
void BuildTree(int i,int left,int right)
{	if(left>=right)		return;
	de[i].left=left;
	de[i].right=right;
	de[i].cover=0;
	if(left==right-1)	return;
	int mid=(left+right)>>1;
	BuildTree(2*i,left,mid);
	BuildTree(2*i+1,mid,right);
}
void PushDown(int i)
{	if(de[i].left!=de[i].right&&de[i].cover!=-2)
	{	de[2*i].cover=de[2*i+1].cover=de[i].cover;
		de[i].cover=-2;
	}
}
void AddQuery(int i,int left,int right,int cover)
{	if(left>=right)		return;
	if(left<=de[i].left&&de[i].right<=right&&de[i].cover!=-2)
	{	de[i].cover+=cover;
		return;
	}
	if(de[i].left==de[i].right-1)	return;
	PushDown(i);
	int mid=(de[i].left+de[i].right)>>1;
	if(right<mid)		AddQuery(2*i,left,right,cover);
	else if(left>=mid)	AddQuery(2*i+1,left,right,cover);
	else
	{	AddQuery(2*i,left,mid,cover);
		AddQuery(2*i+1,mid,right,cover);
	}
}
double GetArea(int i,int left,int right,double height)
{	if(left>=right)		return 0;
	if(de[i].cover>=1)
	{	int x=de[i].left,y=de[i].right;
		return height*(Map[y]-Map[x]);
	}
	if(de[i].left==de[i].right-1)		return 0;
	int mid=(de[i].left+de[i].right)>>1;
	if(right<mid)		return GetArea(2*i,left,right,height);
	else if(left>=mid)	return GetArea(2*i+1,left,right,height);
	else
	{	double sum=0;
		sum+=GetArea(2*i,left,mid,height);
		sum+=GetArea(2*i+1,mid,right,height);
		return sum;
	}
}
void DiscretSolve()
{	int i,x,y;
	sort(Map.begin(),Map.end());
	Map.erase(unique(Map.begin(),Map.end()),Map.end());	
	for(i=0;i<n;++i)
	{	x=lower_bound(Map.begin(),Map.end(),Data[i].x1)-Map.begin();
		y=lower_bound(Map.begin(),Map.end(),Data[i].x2)-Map.begin();
		line.push_back(Line(x,y,Data[i].y1,1));
		line.push_back(Line(x,y,Data[i].y2,-1));
	}
	sort(line.begin(),line.end());
	BuildTree(1,0,Map.size()-1);
}
void AreaUnion()
{	int i;
	double ans=0;
	AddQuery(1,line[0].left,line[0].right,line[0].weight);
	for(i=1;i<line.size();++i)
	{	ans+=GetArea(1,0,Map.size()-1,line[i].y-line[i-1].y);
		AddQuery(1,line[i].left,line[i].right,line[i].weight);
	}
	printf("Total explored area: %.2lf\n",ans);
}
int main()
{	int i,len=1;
	double a,b,c,d;
	while(~scanf("%d",&n))
	{	if(!n)	break;
		Map.clear();
		line.clear();
		for(i=0;i<n;++i)
		{	scanf("%lf%lf%lf%lf",&Data[i].x1,&Data[i].y1,&Data[i].x2,&Data[i].y2);
			Map.push_back(Data[i].x1);
			Map.push_back(Data[i].x2);
		}
		DiscretSolve();
		printf("Test case #%d\n",len++);
		AreaUnion();
		puts("");
	}
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值