HDU 1255 覆盖的面积

/*
做这题的时候是参考别人的程序
现在拿出来回顾下
好好理解一下这题的思路
第一,这题需要离散化
第二,计算矩形并的面积 当某一条线段被覆盖两次或两次以上 计算一次面积 具体的画个图比较明了
第三,也是最重要的,线段数once, more的更新, 当时没有掌握到线段数的精髓 也是迷迷糊糊的,
现在回来想想,once more 是第一类信息 表示当前区间的性质
所有递归回来的时候 由递推关系更新once more 而more 又是由once 推出来的 
*/
#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#define EPS 1e-8

#define L(x) ((x) << 1)

#define R(x) ((x) << 1 | 1)



const int MAXN = 2222;

struct Line

{

	double x,y1,y2;

	int flag;

};

bool equal(double a, double b){

	if( fabs(a - b) <= EPS)

		return true;

	return false;

}

int doubleCmp(const void *a, const void *b){

	return *(double*)a - *(double*)b > 0 ? 1 : -1;

}

int cmp(const void *a, const void *b){

	Line *l1 = (Line*)a;

	Line *l2 = (Line*)b;

	if( equal(l1 -> x, l2 -> x)){

		return l1 -> flag - l2 -> flag;

	}

	return (l1 -> x) - (l2 -> x) > 0 ? 1 : -1;	//浮点数比较大小 要注意

}



struct segTree

{

	int l,r;	

	int cov;		//覆盖次数

	double once, more;	//覆盖一次的长度和覆盖两次的长度

};



Line line[2 * MAXN];

segTree tree[MAXN * 4];		//空间

double pointy[2 * MAXN];



void bulid(int left, int right, int t){

	tree[t].l = left;

	tree[t].r = right;

	tree[t].cov = 0;

	tree[t].once = tree[t].more = 0.0;

	tree[L(t)].cov = 0;

	tree[L(t)].once = tree[L(t)].more = 0.0;

	tree[R(t)].cov = 0;

	tree[R(t)].once = tree[R(t)].more = 0.0;

	if( right - left == 1)

		return;

	int mid = (left + right) >> 1;

	

	bulid(left, mid, L(t));

	bulid(mid, right, R(t));

}





int bsearch(int l, int r, double temp){

	

	while(l <= r){

		int mid = ( l + r ) >> 1; 

		if( equal(pointy[mid], temp)){

			return mid;

		} else if( pointy[mid] > temp ){

			r = mid - 1;

		} else if(pointy[mid] < temp){

			l = mid + 1;

		}

	}

	return -1;

}

void rr(int t,int l, int r){
	//分情况讨论

	if(tree[t].cov > 1){	//覆盖多次

		tree[t].once = 0;

		tree[t].more = pointy[r] - pointy[l];

	} else if( tree[t].cov == 1){	//覆盖一次 则覆盖两次的长度为儿子覆盖一次和两次的长度之和 覆盖一次的长度则为总长度减去覆盖多次的长度 因为不可能存在没被覆盖的区域

		tree[t].more = tree[L(t)].more + tree[R(t)].more 

			+ tree[L(t)].once + tree[R(t)].once;

		tree[t].once = pointy[r] - pointy[l] - tree[t].more;

	} else {	// == 0 没被覆盖

		if( r - l == 1){			//叶子

			tree[t].once = tree[t].more = 0;

		} else {				//由左右孩子的once more 更新自己的once more

			tree[t].once = tree[L(t)].once + tree[R(t)].once;

			tree[t].more = tree[L(t)].more + tree[R(t)].more;

		}

	}

}



void update(int l, int r, int t, int flag){
	/*这递归不是我的风格 哈哈 真是copy啊*/

	if( l >= tree[t].r || r <= tree[t].l)	//不在这个区间 

		return;

	if( l <= tree[t].l && r >= tree[t].r){ 	//包含这个区间

		tree[t].cov += flag;

		rr(t,tree[t].l,tree[t].r);	//如果覆盖区间 则rr once more 然后直接返回 

		return; 			//important	

	}

	update(l, r, L(t), flag);

	update(l, r, R(t), flag);

	rr(t,tree[t].l,tree[t].r);		//rr函数更新节点的once more

}





int main(){

	int t, n, i, j;

	double x1, x2, y1, y2;

	scanf("%d",&t);

	while( t-- ){

		scanf("%d",&n);

		j = 1;

		for(i = 1; i <= n; i++){

			scanf("%lf%lf%lf%lf",&x1, &y1, &x2, &y2);

			line[j].x = x1;

			line[j].y1 = y1;

			line[j].y2 = y2;

			line[j].flag = 1;

			pointy[j] = y1;

			j++;

			line[j].x = x2;

			line[j].y1 = y1;

			line[j].y2 = y2;

			line[j].flag = -1;

			pointy[j] = y2;

			j++;

		}

		qsort(pointy + 1, 2 * n , sizeof(pointy[0]), doubleCmp);

		qsort(line + 1, 2 * n , sizeof(line[0]), cmp);

		//离散化

		int size = 1;

		for(i = 2; i <= 2 * n; i++){

			if(!equal(pointy[i] , pointy[i - 1])){

				pointy[++size] = pointy[i];

			}

		}

		bulid(1, size, 1);

		double ans = 0.0;

		for(i = 1; i <= 2 * n; i++){

			if(i != 1){

				ans += (line[i].x - line[i - 1].x) * tree[1].more;

			}

			int y1 = bsearch(1, size, line[i].y1);

			int y2 = bsearch(1, size, line[i].y2);

			update(y1, y2, 1, line[i].flag);

		}

		printf("%.2lf\n",ans);

	}

	return 0;

}

posted @ 2011-04-12 16:03  L..  阅读(984)  评论(1编辑  收藏  举报