标签:UI blog math 清空 ons print cal ant pac
2 10 10 20 20 15 15 25 25.5 0Sample Output
Test case #1 Total explored area: 180.00
就是给定你2若干个矩形,求覆盖的面积。
看数据范围,就要用离散化来做,我们可以使用扫描线,沿着x轴扫过去,将每一个x坐标所对应的y的上下界用线段树表示出来,当一个矩形入边加入的时候就+1,否则就-1,然后算出面积就可以了。
具体看代码,我写了一些较为详细的注释。
#pragma GCC optimize("O2")
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<ctype.h>
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+(r-l)/2)
#define maxn 500
#define LL long long
using namespace std;
struct TREE{int l,r,c;double cnt,lf,rf;}tr[maxn*4];//l,r存线段树的下标,c存+1-1,就是这颗扫描线扫过的矩形的数量,cnt存答案,也就是一段区间,lf,rf为区间的左右界 
struct Line{double x,y1,y2;int c;}line[maxn];
int m=0,n;
double y[maxn];
bool cmp(Line a,Line b){return a.x<b.x;}
void build(int l,int r,int rt)//离散化,坐标一一对应 
{
	tr[rt].l=l;tr[rt].r=r;
	tr[rt].cnt=tr[rt].c=0;
	tr[rt].lf=y[l],tr[rt].rf=y[r];
	if(l+1==r) return;//左闭右开的区间 
	build(l,mid,ls);
	build(mid,r,rs);//同上所以不是mid+1 
}//说一下区间为什么要 左闭右开,因为这样在计算面积的时候就不用+1-1,就不会出现细节上的错误 
void getlen(int rt)
{
	if(tr[rt].c)
	{
		tr[rt].cnt=tr[rt].rf-tr[rt].lf;
	//	tr[rt].c=0;//注意这里不能清空,应该在下一条出边加入的时候才能清空 
		return ;
	}
	if(tr[rt].l+1==tr[rt].r) tr[rt].cnt=0;//如果是一个节点而不是区间 
	else tr[rt].cnt=tr[ls].cnt+tr[rs].cnt;
	return ;
}
void update(int rt,Line e)
{
	if(e.y1==tr[rt].lf&&e.y2==tr[rt].rf)
	{
		tr[rt].c+=e.c;
		getlen(rt);
		return ;
	}
	if(e.y2<=tr[ls].rf) update(ls,e);//左儿子和右儿子要分开计算 
	else if(e.y1>=tr[rs].lf) update(rs,e);
	else
	{
		Line tmp=e;
		tmp.y2=tr[ls].rf; update(ls,tmp);
		tmp=e;
		tmp.y1=tr[rs].lf; update(rs,tmp);
	}
	getlen(rt);
}
void input()
{
	double x1,x2,y1,y2;
	for(int i=1;i<=n;i++)
	{
		cin>>x1>>y1>>x2>>y2;
		line[++m].x=x1;line[m].y1=y1;line[m].y2=y2;line[m].c=1;
		y[m]=y1;
		line[++m].x=x2;line[m].y1=y1;line[m].y2=y2;line[m].c=-1;
		y[m]=y2;
	}
	sort(line+1,line+m+1,cmp);
	sort(y+1,y+m+1);//坐标离散化 
}
void init()//记得初始化 
{
	memset(tr,0,sizeof(tr));
	m=0;
	memset(line,0,sizeof(line));
	memset(y,0,sizeof(y));
}
int main()
{
	int kase=0;
	while(cin>>n&&n)
	{
		init();
		input();
		build(1,m,1);
		update(1,line[1]);//先加入第一条线 
		double ans=0;
		for(int i=2;i<=m;i++)
		{
			ans+=tr[1].cnt*(line[i].x-line[i-1].x);//标准的面积计算公式 
			update(1,line[i]);
		}
		printf("Test case #%d\n", ++kase);
		printf("Total explored area: %.2lf\n\n",ans);
	}
	return 0;
}
/*
2
1 1 3 3
2 2 4 4
*/
标签:UI blog math 清空 ons print cal ant pac
原文地址:http://www.cnblogs.com/foreverpiano/p/7073112.html