Poj 1255 覆盖的面积 2014-07-28 12:29 116人阅读 评论(0) 收藏

覆盖的面积

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3553    Accepted Submission(s): 1743


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


 

Input
输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N&lt;=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

#include<iostream>
#include<cstdio>
#include<algorithm> 
#define Max 10005
using namespace std;
struct line{
	double x, y1, y2;
	int flag;
}x_line[Max];

struct node{
	int l, r, flag;
	double x, f;
}tree[Max];

double point[Max];
int n, m, xm;

int cmp(double a,double b)
{
	return a<b;
}

bool comp(line a,line b)
{
    return a.x<b.x;
}

void Build(int l,int r,int k)
{
	int m;
	tree[k].l = l;
	tree[k].r = r;
	tree[k].flag = 0;
	tree[k].x = 0.0;
	tree[k].f = 0.0;
	if(l+1 == r)	return;
	m = (l+r)>>1;
	Build(l,m,k+k);
	Build(m,r,k+k+1);
}

void Myscanf()
{
	m = 1;
	double x1,x2,y1,y2;
	scanf("%d",&n);
	for(int i=0; i<n; i++)
	{
		scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
		point[m] = y1;
		x_line[m].x = x1;
		x_line[m].y1 = y1;
		x_line[m].flag = 1;
		x_line[m++].y2 = y2;
		point[m] = y2;
		x_line[m].x = x2;
		x_line[m].y1 = y1;
		x_line[m].flag = -1;
		x_line[m++].y2 = y2;
	}
	
}

void Point_Do()
{
	int mi = 0;
	sort(point+1,point+m,cmp);
	sort(x_line+1,x_line+m,comp);
	xm = m;
	for(int i=1; i<m; i++)
	{
		if(point[i]!=point[mi])		point[++mi] = point[i]; 		//去重
	}
	m = mi;
}

int Bin(double xi)
{
	int l = 1, r = m;
	int mi;
	while(l<=r)
	{
		mi = (l+r)>>1;
		if(xi == point[mi])	return mi;
		if(xi > point[mi])	l = mi+1;
		else r = mi-1;
	}
	return -1;
}

void update(int l, int r, int k, line cur)
{
	if(tree[k].l==tree[k].r-1)
	{
		if(tree[k].flag == 1 && cur.flag == 1)	tree[k].f = cur.x;
		else if(tree[k].flag==2 && cur.flag==-1){
			tree[k].x +=( cur.x - tree[k].f );
			tree[k].f = 0.0;
		}
		tree[k].flag+=cur.flag;	
		return;
	}
	int mi = (tree[k].l+tree[k].r)>>1;
	if(l>=mi)	update(l,r,k+k+1,cur);
	else if(r<=mi)	update(l,r,k+k,cur);
	else{
		update(l,mi,k+k,cur);
		update(mi,r,k+k+1,cur);
	}
	return;
}

double query(int k)
{
	if(tree[k].l + 1==tree[k].r)	return (point[tree[k].r]-point[tree[k].l])*tree[k].x;
	return query(k+k) + query(k+k+1);
}

int Ans()
{
	for(int i=1;i<xm;i++)
	{
		int x = Bin(x_line[i].y1);
		int y = Bin(x_line[i].y2);
		update(x,y,1,x_line[i]);
	}
}

int main()
{
	int Case;
	scanf("%d",&Case);
	while(Case--)
	{
		memset(tree,0,sizeof(tree));
		memset(point,-1,sizeof(point));
		memset(x_line,0,sizeof(x_line));
		Myscanf();
		Point_Do();
		Build(1,m,1);
		Ans();
		printf("%.2lf
",query(1));		
	}

	return 0;
}

主要思路就是将y轴离散为线段树,然后,将x轴转换为状态,其实也可以x为线段树,y为状态的


版权声明:本文为博主原创文章,未经博主允许不得转载。

本文为博主原创文章,未经博主允许不得转载。
原文地址:https://www.cnblogs.com/you-well-day-fine/p/4671650.html