线段树对面积的划分 HDU 1541

题目大意是对给定的很多矩形,求出面积和,重叠的部分只能算一次

可以对x和y坐标进行离散化,然后对面积进行划分,划分成四部分,左上,右上,左下,右下

与之前的线段式线段树不同的是,每次对宽和高进行等分的时侯,xmid和ymid在各部分出现的时候不用+1,因为这里算的是面积,面积是连续的

注意浮点数的判断大小

对于x,y是否相等,只有在x+0.000001 > y && x - 0.000001 < y时成立

对于x<y,只有在x+ 0.000001 < y时成立

对于x<=y,只有在x-0.000001 <y时成立


我的代码

#include<stdio.h>

struct Node
{
	int left;
	int right;
	int up;
	int down;
	double area;
	int flag;
}node[1000001];

double x[201], y[201];
int xnum, ynum;

double area[101][4];

int n;

double Max(double a, double b)
{
	return a > b ? a : b;
}

double Min(double a, double b)
{
	return a < b ? a : b;
}

bool smaller(double a, double b)
{
	if(a - 0.000001 < b)
		return 1;
	return 0;
}

bool biger(double a, double b)
{
	if(a + 0.000001 > b)
		return 1;
	return 0;
}

int equal(double a, double b)
{
	if(a + 0.000001 >= b && a - 0.000001 <= b)
		return 1;
	return 0;
}

int sort(double *array, int& num)
{
	int i, j;
	for(i = 1; i < num; i ++)
	{
		for(j = i + 1; j <= num; j ++)
		{
			if(equal(array[i], array[j]))
			{
				array[j] = array[num];
				num --;
				j --;
			}
		}
	}

	for(i = 1; i < num; i ++)
		for(j = i + 1; j <= num; j ++)
		{
			if(array[i] > array[j])
			{
				array[i] += array[j];
				array[j] = array[i] - array[j];
				array[i] = array[i] - array[j];
			}
		}
		return 0;
}

int build(int xleft, int xright, int yup, int ydown, int pre)
{

	node[pre].left = xleft;
	node[pre].right = xright;
	node[pre].up = yup;
	node[pre].down = ydown;
	node[pre].area = 0;
	node[pre].flag = 0;

	if((xleft + 1 == xright || xleft == xright) && (ydown + 1 == yup || ydown == yup))
		return 1;

	int xmid = (xleft + xright) / 2, ymid = (yup + ydown) / 2;
	build(xleft, xmid, yup, ymid, pre * 4);
	build(xmid, xright, yup, ymid, pre * 4 + 1);
	build(xleft, xmid, ymid, ydown, pre * 4 + 2);
	build(xmid, xright, ymid, ydown, pre * 4 + 3);
	return 0;
}

int overlay(double l, double r, double u, double d, double l1, double r1, double u1, double d1, double *over)
{
	if(smaller(r, l1) || biger(l, r1) || smaller(u, d1) || biger(d, u1))
	{
		return 0;
	}
	over[0] = Max(l, l1);
	over[1] = Min(r, r1);
	over[2] = Min(u, u1);
	over[3] = Max(d, d1);
	if(smaller(over[1], over[0]))
		return 0;
	if(smaller(over[2], over[3]))
		return 0;
	return 1;
}

int insert(double l, double r, double u, double d, int pre)
{
	double over[4];
	if(equal(l, x[node[pre].left]) && equal(r, x[node[pre].right]) && equal(u, y[node[pre].up]) && equal(d, y[node[pre].down]))
	{
		node[pre].area = (u - d) * (r - l);
		node[pre].flag = 1;
		return 0;
	}
	if(!node[pre * 4].flag && overlay(l, r, u, d, x[node[pre * 4].left], x[node[pre * 4].right], y[node[pre * 4]. up], y[node[pre * 4].down], over))
	{
		insert(over[0], over[1], over[2], over[3], pre * 4);
	}
	if(!node[pre * 4 + 1].flag && overlay(l, r, u, d, x[node[pre * 4 + 1].left], x[node[pre * 4 + 1].right], y[node[pre * 4 + 1]. up], y[node[pre * 4 + 1].down], over))
	{
		insert(over[0], over[1], over[2], over[3], pre * 4 + 1);
	}
	if(!node[pre * 4 + 2].flag && overlay(l, r, u, d, x[node[pre * 4 + 2].left], x[node[pre * 4 + 2].right], y[node[pre * 4 + 2]. up], y[node[pre * 4 + 2].down], over))
	{
		insert(over[0], over[1], over[2], over[3], pre * 4 + 2);
	}
	if(!node[pre * 4 + 3].flag && overlay(l, r, u, d, x[node[pre * 4 + 3].left], x[node[pre * 4 + 3].right], y[node[pre * 4 + 3]. up], y[node[pre * 4 + 3].down], over))
	{
		insert(over[0], over[1], over[2], over[3], pre * 4 + 3);
	}

	node[pre].area = node[pre * 4].area + node[pre * 4 + 1].area + node[pre * 4 + 2].area + node[pre * 4 + 3].area;
	return 0;

}

int main()
{
	int i, ca = 0;
	while(scanf("%d", &n) != EOF && n != 0)
	{
		xnum = 0;
		ynum = 0;
		for(i = 1; i <= n; i ++)
		{
			scanf("%lf%lf%lf%lf", &area[i][0], &area[i][1], &area[i][2], &area[i][3]);
			x[++ xnum] = area[i][0];
			x[++ xnum] = area[i][2];

			y[++ ynum] = area[i][1];
			y[++ ynum] = area[i][3];
		}
		sort(x, xnum);
		sort(y, ynum);

		build(1, xnum, ynum, 1, 1);
		for(i = 1; i <= n; i ++)
		{
			insert(area[i][0], area[i][2], area[i][3], area[i][1], 1);
		}
		printf("Test case #%d\nTotal explored area: %.2lf\n\n", ++ ca, node[1].area);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值