51nod 1206:Picture 求覆盖周长

题目来源: IOI 1998
基准时间限制:2 秒 空间限制:131072 KB 分值: 160 难度:6级算法题
 收藏
 关注
给出平面上的N个矩形(矩形的边平行于X轴和Y轴),求这些矩形组成的所有多边形的周长之和。

例如:N = 7。(矩形会有重叠的地方)。

合并后的多边形:


多边形的周长包括里面未覆盖部分方块的周长。
Input
第1行:1个数N。(2 <= N <= 50000)
第2 - N + 1行,每行4个数,中间用空格分隔,分别表示矩形左下和右上端点的坐标。(-1000000 <= X[i], Y[i] <= 1000000)
Output
输出多边形的周长。
Input示例
7
-15 0 5 10
-5 8 20 25
15 -4 24 14
0 -6 16 4
2 15 10 22
30 10 36 20
34 0 40 16
Output示例
228

最近真的是被线段树扫描线搞得心力憔悴,刚刚才把poj上面求面积的弄懂,然后又遇到了求周长的。

思想和求面积是差不多的,变化就是多了一个line,就是当前的线段树分成了几段,这个在求面积的时候不会用到,但是求周长会用到。比如[1,1][2,2]就只有1段,[1,1][3,3]在线段树[1,3]的节点中就分成了两段。

第二点就是注意

tree[root].interval=tree[root*2+1].interval+tree[root*2+2].interval-tree[root*2+1].Rcover*tree[root*2+2].Lcover;

计算分成了多少块 是左子树的分块数+右子树的分块数,为了防止左子树的右边和右子树的左边连在一块,所以还要把这部分扣掉。

第三点就是注意排序,如果在x值相等的情况下,要将入边放在前面先处理,出边后处理。

代码:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
#pragma warning(disable:4996)
using namespace std;

struct li
{
	int x,y1,y2;
	int bLeft;
}line[500005];

int y[500005];
int n;

struct no
{
	int L;
	int R;
	int cover;
	int Lcover;
	int Rcover;
	int interval;
	int m;
}tree[500005];

void buildtree(int root,int L,int R)
{
	tree[root].L=L;
	tree[root].R=R;
	tree[root].cover=0;
	tree[root].Lcover=0;
	tree[root].Rcover=0;
	tree[root].interval=0;
	tree[root].m=0;

	if(L!=R)
	{
		int mid = (L+R)/2;
		buildtree(root*2+1,L,mid);
		buildtree(root*2+2,mid+1,R);
	}
}

void insert(int root,int L,int R)
{
	if(tree[root].L==L&&tree[root].R==R)
	{
		tree[root].cover++;
		tree[root].m = y[R+1]-y[L];
		tree[root].Lcover=1;
		tree[root].Rcover=1;
		tree[root].interval=1;
		return;
	}
	else
	{
		int mid = (tree[root].L + tree[root].R)/2;
		if(R<=mid)
		{
			insert(root*2+1,L,R);
		}
		else if(L>=mid+1)
		{
			insert(root*2+2,L,R);
		}
		else
		{
			insert(root*2+1,L,mid);
			insert(root*2+2,mid+1,R);
		}
	}
	if(tree[root].cover==0)
	{
		tree[root].m = tree[root*2+1].m +tree[root*2+2].m;
		tree[root].Lcover=tree[root*2+1].Lcover;
		tree[root].Rcover=tree[root*2+2].Rcover;
		tree[root].interval=tree[root*2+1].interval+tree[root*2+2].interval-tree[root*2+1].Rcover*tree[root*2+2].Lcover;
	}
}

void dele(int root,int L,int R)
{
	if(tree[root].L==L&&tree[root].R==R)
	{
		tree[root].cover--;
	}
	else
	{
		int mid = (tree[root].L + tree[root].R)/2;
		if(R<=mid)
		{
			dele(root*2+1,L,R);
		}
		else if(L>=mid+1)
		{
			dele(root*2+2,L,R);
		}
		else
		{
			dele(root*2+1,L,mid);
			dele(root*2+2,mid+1,R);
		}
	}
	if(tree[root].cover<=0&&tree[root].L==tree[root].R)
	{
		tree[root].m=0;
		tree[root].Lcover=0;
		tree[root].Rcover=0;
		tree[root].interval=0;
	}
	else if(tree[root].cover<=0)
	{
		tree[root].m = tree[root*2+1].m +tree[root*2+2].m;
		tree[root].Lcover=tree[root*2+1].Lcover;
		tree[root].Rcover=tree[root*2+2].Rcover;
		tree[root].interval=tree[root*2+1].interval+tree[root*2+2].interval-tree[root*2+1].Rcover*tree[root*2+2].Lcover;
	}
}

bool cmp(struct li line1, struct li line2)
{
	if (line1.x == line2.x)
		return line1.bLeft > line2.bLeft;
	return (line1.x < line2.x);
}

template <class F,class T>  
F bin_search(F s,F e,T val)  
{  
	F L = s;  
	F R = e-1;  

	while(L<=R)  
	{  
		F mid = L + (R-L)/2;  
		if(!(*mid<val || val < *mid))  
		{  
			return mid;  
		}  
		else if(val < *mid)  
		{  
			R = mid -1;  
		}  
		else  
		{  
			L= mid + 1;  
		}  
	}  
}  

int main()
{	
	//freopen("i.txt","r",stdin);
	//freopen("o.txt","w",stdout);

	int i,x1,x2,y1,y2,yc,lc;
	scanf("%d",&n);

	yc=0;
	lc=0;
	for(i=0;i<n;i++)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		y[yc++]=y1;
		y[yc++]=y2;

		line[lc].x=x1;
		line[lc].y1=y1;
		line[lc].y2=y2;
		line[lc].bLeft = 1;
		lc++;

		line[lc].x=x2;
		line[lc].y1=y1;
		line[lc].y2=y2;
		line[lc].bLeft = 0;
		lc++;
	}
	sort(line,line+lc,cmp);
	sort(y,y+yc);
	yc=unique(y,y+yc)-y;

	buildtree(0,0,yc-1-1);
	int preme=0;
	int now_m=0;
	int now_line=0;
	for(i=0;i<=lc-1;i++)
	{
		int L=bin_search(y,y+yc,line[i].y1)-y;  
		int R=bin_search(y,y+yc,line[i].y2)-y;  

		if(line[i].bLeft)  
		{  
			insert(0,L,R-1);  
		}  
		else  
		{  
			dele(0,L,R-1);  
		}
		if(i>=1)
			preme += 2*now_line*(line[i].x-line[i-1].x);
		preme += abs(tree[0].m-now_m);
		now_m=tree[0].m;
		now_line=tree[0].interval;
	}
	printf("%d\n",preme);
	//system("pause");
	return 0;
}


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

posted on 2015-10-06 11:31  光速小子  阅读(222)  评论(0编辑  收藏  举报

导航