CodeVS3044矩形面积求并

CodeVS3044矩形面积求并  题解
题目描述 Description

输入n个矩形,求他们总共占地面积(也就是求一下面积的并)

输入描述 Input Description

可能有多组数据,读到n=0为止(不超过15组)

每组数据第一行一个数n,表示矩形个数(n<=100)

接下来n行每行4个实数x1,y1,x2,y1(0 <= x1 < x2 <= 100000;0 <= y1 < y2 <= 100000),表示矩形的左下角坐标和右上角坐标

输出描述 Output Description

每组数据输出一行表示答案

样例输入 Sample Input
2
10 10 20 20
15 15 25 25.5
0
样例输出 Sample Output
180.00
数据范围及提示 Data Size & Hint

        用线段树做了一天仍然做不出来,表示抓狂>_<
        结果是我最后用了不到30分钟不加线段树就做出来了。。。。
        言归正传:这道题在各大省都要被讲烂了有木有。。“官方”做法是用离散化+线段树,我曾经多次在不同场合提出:怎么用线段树维护?可是都被斥责了,说这么简单的事让我自己想。然而我IQ不够,到现在也没有想粗来^_^,于是就只用了离散化,然而很乐观的是我竟然AC了。(如果以后会用线段树了再回来改)。
        关于离散:我们容易看到在如此硕大的坐标系上(10^6*10^6,还是浮点)竟然只有区区100个矩形,就很容易想到离散化,我们不是要用扫描线吗,本来是要用线段树维护y轴上的覆盖长度的,现在换成一维数组。我们就先开10^7这么大的数组(还有一位小数),很明显会爆空间(我试了),而且假如所有的矩形都是充满坐标系的那种大矩形,处理100次,每次都给整个数组赋值,也会超时。但我们发现对于这样的一段区域:它的下界是某个矩形的边的纵坐标,它的上界也是某个矩形的边的纵坐标,而且着两条边的纵坐标之间没有其他的边,那么这一段区域在整个的操作中要么被全部+1,要么被全部-1,我们就把它看作一个整体,每次直接给这个整体+1或-1,一共有100个矩形,就有200条矩形的上下边,能够把整个y轴划分成200个这样的区间,而刚说了每次只对这样的区间进行修改,每次最多修改次数就从10^7降到了200,整个算法的时间复杂度就是O(n^2),对于n=100,足够了
代码如下:
//CodeVS3044举行面积求并 离散化 
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
double hash[500], a[500];
int N, tot, v[500];
struct edge
{
	double x, down, up;int flag;
	bool operator<(edge t)const{return x<t.x;}
}e[500];
void input()
{
	int i, t=0;
	double x1, y1, x2, y2;
	tot=0; 
	for(i=1;i<=N;i++)
	{
		scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
		e[i].x=x1;e[i].down=y1;e[i].up=y2;e[i].flag=1;
		e[i+N].x=x2;e[i+N].down=y1;e[i+N].up=y2;e[i+N].flag=-1;
		a[++t]=y1;a[++t]=y2;
	}
	sort(a+1,a+t+1);
	for(i=1;i<=t;i++)if(a[i]!=a[i-1])hash[++tot]=a[i];
}
void change(double L, double R, int flag)
{
	int i, l ,r;
	for(i=0;hash[i]<=L;i++);l=i;
	for(i=tot;hash[i]>R;i--);r=i;
	for(i=l;i<=r;i++)v[i]+=flag;
}
double cha()
{
	int i;
	double ans=0;
	for(i=1;i<=tot;i++)if(v[i]>0)ans+=(hash[i]-hash[i-1]);
	return ans;
}
int main()
{
	int i, j;
	double ans;
	while(scanf("%d",&N),N!=0)
	{
		input();
		sort(e+1,e+N+N+1);
		ans=0;
		for(i=1;i<=N+N;i++)
		{
			ans+=cha()*(e[i].x-e[i-1].x);
			change(e[i].down,e[i].up,e[i].flag);
		}
		printf("%.2lf\n",ans);
	}
}
测试点#a1.in  结果:    内存使用量:  256kB     时间使用量:  0ms     
测试点#a10.in 结果: 内存使用量: 256kB 时间使用量: 2ms
测试点#a2.in 结果: 内存使用量: 256kB 时间使用量: 0ms
测试点#a3.in 结果: 内存使用量: 256kB 时间使用量: 0ms
测试点#a4.in 结果: 内存使用量: 256kB 时间使用量: 3ms
测试点#a5.in 结果: 内存使用量: 256kB 时间使用量: 3ms
测试点#a6.in 结果: 内存使用量: 256kB 时间使用量: 3ms
测试点#a7.in 结果: 内存使用量: 256kB 时间使用量: 3ms
测试点#a8.in 结果: 内存使用量: 256kB 时间使用量: 3ms
测试点#a9.in 结果: 内存使用量: 256kB 时间使用量: 3ms


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值