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

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(扫描线+矩形周长并)

时间: 2024-10-14 04:27:49

poj 1177 Picture(扫描线+矩形周长并)的相关文章

POJ 1177 Picture(扫描线求周长)

与求面积并的差不多,但是这个与扫描的方向相同的情况不太好处理,如果扫描线离散化两次扫两遍其实也可以解决这个问题,但是这样无论在时间还是空间上稍微就有点浪费了啊.这里因为我是离散x坐标的所以对于平行于y轴的方向上的统计比较难统计.处理的方法是:标记区间左边的断点,和右边的断点,求出这个区间一共有多少个断点.就可以统计出平行于y轴的长度了.这里合并的时候需要判断右边的左区间和左边的右区间是否相同,如果相同的话,说明他们连接到了一起,要减去多加的. Picture Time Limit: 2000MS

N - Picture - poj 1177(扫描线求周长)

题意:求周长的,把矩形先进行融合后的周长,包括内周长 分析:刚看的时候感觉会跟棘手,让人无从下手,不过学过扫描线之后相信就很简单了吧(扫描线的模板- -),还是不说了,下面是一精确图,可以拿来调试数据 ***************************************************************************************************************** #include<stdio.h>#include<math.

hdu1828 (Picture) &amp;poj 1177( Picture)&amp;sdibt 2390(5.5.1 Picture 矩形周长)(线段树+扫描)

题目地址:hdu1828 (Picture)  & poj 1177( Picture) & sdibt 2390(5.5.1 Picture 矩形周长) 题目大意: 给你N个矩形,求出N个矩形构成的周长. 解题思路: 线段数+扫描线. 推荐博客: POJ1177 Picture(线段树求轮廓周长) POJ 1177 Picture (线段树+离散化+扫描线) 详解 注意事项: 该题在求面积的基础上有了升级,多写了一个被调需要求出投影与Y轴有几段,不然样例会少算20,就是给出图形中间的小矩

扫描线矩形周长的并 POJ1177

1 //扫描线矩形周长的并 POJ1177 2 // 我是按x轴 3 4 #include <iostream> 5 #include <cstdio> 6 #include <cstdlib> 7 #include <algorithm> 8 #include <vector> 9 #include <cmath> 10 #include <cstring> 11 // #include <memory.h>

HDU 1828 / POJ 1177 Picture --线段树求矩形周长并

题意:给n个矩形,求矩形周长并 解法:跟求矩形面积并差不多,不过线段树节点记录的为: len: 此区间线段长度 cover: 此区间是否被整个覆盖 lmark,rmark: 此区间左右端点是否被覆盖 num: 此区间分离开的线段的条数 重点在转移的地方,不难理解. 代码: #include <iostream> #include <cmath> #include <iostream> #include <cstdio> #include <cstrin

HDU 1828 Picture(矩形周长并)

HDU 1828 Picture 题目链接 题意:给定n个矩形,输出矩形周长并 思路:利用线段树去维护,分别从4个方向扫一次,每次多一段的时候,就查询该段未被覆盖的区间长度,然后周长就加上这个长度,4个方向都加完就是答案 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 5005; int n; struct Rec { int

poj 1177 Picture 线段树辅助解扫描线 矩形周长并

题目链接:http://poj.org/problem?id=1177 分析:对扫描线不太理解~~~ 第一题~~ 留个坑. 代码: /* *********************************************** Author :ltwy Created Time :2015年01月17日 星期六 18时06分53秒 File Name :1.cpp ************************************************ */ #include <s

poj 1177 Picture(线段树周长并)

题目链接:http://poj.org/problem?id=1177 题意:给你n个矩形问你重叠后外边缘总共多长. 周长并与面积并很像只不过是处理的时候是   增加的周长=abs(上一次的线段的长度-更新后线段的长度) 然后分别处理一下竖着的边和横着的边就好了即建两次树就好. 就是一道典型的周长并问题,可以拿来练练周长并的写法. #include <iostream> #include <cstring> #include <algorithm> #include &

poj-1177 Picture(矩形周长并,线段树+扫描线)

题目链接:点击打开链接 Picture Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 11706   Accepted: 6175 Description A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical o