码迷,mamicode.com
首页 > 其他好文 > 详细

poj 1177 Picture(扫描线+矩形周长并)

时间:2014-08-15 14:43:08      阅读:301      评论:0      收藏:0      [点我收藏+]

标签:扫描线   面积并   

http://poj.org/problem?id=1177


求矩形的周长并,明确的一点是对于覆盖的边的长度忽略不计。

与求面积并类似,首先离散化,对矩形的每条横边从下往上扫描。扫描过程中要完成三个任务,更新相应的区间信息,求横边长,求竖边长。


节点信息:

l,r:左右区间编号

cnt:表示该区间是否被完全覆盖。cnt > 0 表示完全覆盖,否则不完全覆盖。

lp,rp:表示该区间的两个端点是否被覆盖,为1被覆盖,为0没被覆盖。

num:该区间被覆盖的线段数目。例如区间[1,10],当更新[2,3][3,5]时,num = 1,因为他们是连续的,当更新[1,2][3,5]时,num = 2,因为这两条线段不连续。记录num是为了求竖边,每扫描一条边,它增加的竖边的数目是2*num。


每扫描一条边,用当前总区间的长度减去上一个总区间的长度取绝对值即是这次增加的横边长。(下一条边的高度 - 这一条的高度)*num*2就是增加的竖边长。

比较好理解的讲解 :http://www.cnblogs.com/scau20110726/archive/2013/04/13/3018687.html

#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL long long
#define _LL __int64
#define eps 1e-12
#define PI acos(-1.0)
using namespace std;
const int maxn = 5010;

struct Line
{
	int x1,x2,y;
	int tag;
	bool operator < (const struct Line &tmp)const
	{
		return y < tmp.y;
	}
}line[maxn*2];

int x[maxn*2];

struct node
{
	int l,r,cnt,len;
	int lp,rp,num;
}tree[maxn*8];

int Binsearch(int l, int r, int key)
{
	int low = l,high = r;
	while(high >= low)
	{
		int mid = (low + high) >> 1;
		if(x[mid] == key)
			return mid;
		if(x[mid] > key)
			high = mid-1;
		else low = mid+1;
	}
	return -1;
}

void build(int v, int l, int r)
{
	tree[v].l = l;
	tree[v].r = r;
	tree[v].cnt = 0;
	tree[v].len = 0;
	tree[v].lp = tree[v].rp = tree[v].num = 0;
	if(l == r)
		return;
	int mid = (l+r)>>1;
	build(v*2,l,mid);
	build(v*2+1,mid+1,r);
}

void maintain(int v)
{
	if(tree[v].cnt > 0) //完全被覆盖
	{
		tree[v].len = x[tree[v].r+1] - x[tree[v].l];
		tree[v].lp = 1;
		tree[v].rp = 1;
		tree[v].num = 1;
		return;
	}
	if(tree[v].l == tree[v].r)
	{
		tree[v].lp = tree[v].rp = tree[v].num = tree[v].len = 0;
		return;
	}
	//该区间不完全被覆盖
	tree[v].len = tree[v*2].len + tree[v*2+1].len;
	tree[v].lp = tree[v*2].lp;
	tree[v].rp = tree[v*2+1].rp;
	tree[v].num = tree[v*2].num + tree[v*2+1].num - (tree[v*2].rp&&tree[v*2+1].lp);
}

void update(int v, int l, int r, int tag)
{
	if(tree[v].l == l && tree[v].r == r)
	{
		tree[v].cnt += tag;
		maintain(v);
		return;
	}

	int mid = (tree[v].l + tree[v].r) >> 1;
	if(r <= mid)
		update(v*2,l,r,tag);
	else if(l > mid)
		update(v*2+1,l,r,tag);
	else
	{
		update(v*2,l,mid,tag);
		update(v*2+1,mid+1,r,tag);
	}
	maintain(v);
}

int main()
{
	int n;
	int cnt,x1,y1,x2,y2;

	while(~scanf("%d",&n))
	{
		cnt = 0;
		for(int i = 1; i <= n; i++)
		{
			scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
			line[++cnt] = (struct Line){x1,x2,y1,1};
			x[cnt] = x1;
			line[++cnt] = (struct Line){x1,x2,y2,-1};
			x[cnt] = x2;
		}
		sort(x+1,x+1+cnt);
		sort(line+1,line+1+cnt);

		int k = 1;
		for(int i = 2; i <= cnt; i++)
		{
			if(x[i] != x[i-1])
				x[++k] = x[i];
		}
		build(1,1,k);
		int ans = 0;
		int pre = 0;
		for(int i = 1; i <= cnt; i++)
		{
			int l = Binsearch(1,k,line[i].x1);
			int r = Binsearch(1,k,line[i].x2)-1;
			update(1,l,r,line[i].tag);
			int t = abs(tree[1].len - pre);
			pre = tree[1].len;
			ans += t;
			if(i < cnt)
				ans += (line[i+1].y-line[i].y)*2*tree[1].num;
		}
		printf("%d\n",ans);
	}
	return 0;
}


poj 1177 Picture(扫描线+矩形周长并),布布扣,bubuko.com

poj 1177 Picture(扫描线+矩形周长并)

标签:扫描线   面积并   

原文地址:http://blog.csdn.net/u013081425/article/details/38583619

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!