HDU 1255-覆盖的面积(线段树+扫描线)

C - 覆盖的面积
Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Submit  Status  Practice  HDU 1255
Appoint description:  System Crawler  (2016-04-30)

Description

给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 


 

Input

输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000. 

注意:本题的输入数据较多,推荐使用scanf读入数据. 
 

Output

对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数. 
 

Sample Input

      
      
      
      
2 5 1 1 4 2 1 3 3 7 2 1.5 5 4.5 3.5 1.25 7.5 4 6 3 10 7 3 0 0 1 1 1 0 2 1 2 0 3 1
 

Sample Output

      
      
      
      
7.63 0.00
AC代码:
/*
这题一开始是想找题解的,所以当我找了题解后,发现
有人一样是不会做这个的,只做了面积并,而且他YY过了
所以我也决定要YY过它,所以就没有看题解了。没想到
过了一晚时间就让我YY过了,哈哈!!
*/

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
#define T 10005
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
int n;
//离散化数组
double pos[T];
//保存y在x区间的边
struct line
{
	double y,x_up,x_down;
	int flag;
	bool operator<(const line& a)const{
		return y<a.y;
	}
	line(double _1,double _2,double _3,int _4):
		y(_1),x_up(_2),x_down(_3),flag(_4){}
	line(){}
}p[T];
//线段树数组
struct node
{
	int L,R;
	double len;
	int mid;
	int flag;
}tree[T];
//向上更新
void pushup(int rt)
{
	if(tree[rt].flag>=2){//完全覆盖区间
		tree[rt].len = pos[tree[rt].R-1]-pos[tree[rt].L-1];
	}
	else if(tree[rt].L+1==tree[rt].R){//叶子节点
		tree[rt].len = 0;
	}
	else//跨越几个区间合并值
	{
		tree[rt].len = tree[lson].len+tree[rson].len;
		/*tree[lson].len = 0,tree[rson].len=0;*/
	}
}
/*
这题与面积并相像,只是多了一个向下更新,之所以要向下
更新是因为,我要的是单个区间都要有值
*/
void pushdown(int rt)
{
	if(tree[rt].flag){
		tree[lson].flag += tree[rt].flag;
		tree[rson].flag += tree[rt].flag;
		tree[rt].flag = 0;
	}
}
//建树
void build(int rt,int L,int R)
{
	tree[rt].L = L;
	tree[rt].R = R;
	tree[rt].flag = 0;
	tree[rt].len = 0;
	tree[rt].mid = (L+R)>>1;
	if(L+1!=R){
		build(lson,L,tree[rt].mid);
		build(rson,tree[rt].mid,R);
	}
}
//更新
void update(int rt,int L,int R,int w)
{
	/*
	一开始答案存在偏差,弄了好久发现只要符合范围就返回
	所以有些区间是将值传递下去了,结果却因为没下去所以
	漏掉了一些面积,之后一直在调整pushdown函数,结果一直
	没结果,换成只在区间才返回后就不存在这种情况了。应该
	可以用懒惰性标记吧
	*/
	if(L<=tree[rt].L&&tree[rt].R<=R&&tree[rt].L+1==tree[rt].R){
		tree[rt].flag+=w;
		pushup(rt);
		return;
	}
	pushdown(rt);
	if(R<=tree[rt].mid)
		update(lson,L,R,w);
	else if(L>=tree[rt].mid)
		update(rson,L,R,w);
	else{
		update(lson,L,tree[rt].mid,w);
		update(rson,tree[rt].mid,R,w);
	}
		pushup(rt);
}
int main()
{
#ifdef zsc
	freopen("input.txt","r",stdin);
#endif
	int i,c,N;
	double x1,x2,y1,y2;
	scanf("%d",&N);
	while(N--)
	{
		scanf("%d",&n);
		c = 0;
		for(i=0;i<n;++i){
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			pos[c] = x1;
			p[c++] = line(y1,x1,x2,1);
			pos[c] = x2;
			p[c++] = line(y2,x1,x2,-1); 
		}
		sort(pos,pos+c);
		int d = unique(pos,pos+c)-pos;
		build(1,1,d);
		sort(p,p+c);
		double ans=0;
		for(i=0;i<c-1;++i){
			//因为离散化了,所以要找x的下标
			int a = lower_bound(pos,pos+d,p[i].x_up)-pos+1;
			int b = lower_bound(pos,pos+d,p[i].x_down)-pos+1;
			//更新x区间(a,b)的值
			update(1,a,b,p[i].flag);
			ans+=tree[1].len*(p[i+1].y-p[i].y);
		}
		printf("%.2lf\n",ans);
	}
	return 0;
}


你可能感兴趣的:(线段树,poj)