hdu1828 Picture

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 3215    Accepted Submission(s): 1679

Problem Description

A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical or horizontal. Each rectangle can be partially or totally covered by the others. The length of the boundary of the union of
all rectangles is called the perimeter.

Write a program to calculate the perimeter. An example with 7 rectangles is shown in Figure 1.

The corresponding boundary is the whole set of line segments drawn in Figure 2.

The vertices of all rectangles have integer coordinates.

Input

Your program is to read from standard input. The first line contains the number of rectangles pasted on the wall. In each of the subsequent lines, one can find the integer coordinates of the lower left vertex and the upper right vertex of each rectangle. The
values of those coordinates are given as ordered pairs consisting of an x-coordinate followed by a y-coordinate.

0 <= number of rectangles < 5000

All coordinates are in the range [-10000,10000] and any existing rectangle has a positive area.

Please process to the end of file.

Output

Your program is to write to standard output. The output must contain a single line with a non-negative integer which corresponds to the perimeter for the input rectangles.

Sample 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

Sample Output

228

Source

IOI 1998

轮廓线确实有些屌………………………………

#include<map>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<climits>
#include<list>
#include<iomanip>
#include<stack>
#include<set>
using namespace std;
int hs[10010];
struct Tree
{
	int l,r,num,cnt,val;
	bool flag_l,flag_r;
}tree[10000<<2];
void create(int l,int r,int k)
{
	tree[k].l=l;
	tree[k].r=r;
	tree[k].val=0;
	tree[k].num=tree[k].cnt=0;
	tree[k].flag_l=tree[k].flag_r=0;
	if(l+1==r)
		return;
	int m=l+r>>1;
	create(l,m,k<<1);
	create(m,r,k<<1|1);
}
void update(int l,int r,int k,int flag)
{
	if(tree[k].l==l&&tree[k].r==r)
	{
		tree[k].num+=flag;
		if(tree[k].num==0)
		{
			tree[k].val=l+1==r?0:tree[k<<1].val+tree[k<<1|1].val;
			if(l+1==r)
			{
				tree[k].cnt=0;
				tree[k].flag_l=tree[k].flag_r=0;
			}
			else
			{
				tree[k].cnt=tree[k<<1].cnt+tree[k<<1|1].cnt;
				if(tree[k<<1].flag_r&&tree[k<<1|1].flag_l)
					tree[k].cnt--;
				tree[k].flag_l=tree[k<<1].flag_l;
				tree[k].flag_r=tree[k<<1|1].flag_r;
			}
		}
		else
		{
			tree[k].cnt=1;
			tree[k].val=hs[r]-hs[l];
			tree[k].flag_l=tree[k].flag_r=1;
		}
		return;
	}
	int m=tree[k].l+tree[k].r>>1;
	if(r<=m)
		update(l,r,k<<1,flag);
	else if(l>=m)
		update(l,r,k<<1|1,flag);
	else
	{
		update(l,m,k<<1,flag);
		update(m,r,k<<1|1,flag);
	}
	if(tree[k].num==0)
	{
		tree[k].val=tree[k<<1].val+tree[k<<1|1].val;
		tree[k].cnt=tree[k<<1].cnt+tree[k<<1|1].cnt;
		if(tree[k<<1].flag_r&&tree[k<<1|1].flag_l)
			tree[k].cnt--;
		tree[k].flag_l=tree[k<<1].flag_l;
		tree[k].flag_r=tree[k<<1|1].flag_r;
	}
}
struct Seg
{
	int flag,l,r,y;
	bool operator <(Seg one)const
	{
		return y<one.y;
	}
}seg[10010];
int main()
{
	int n;
	while(cin>>n)
	{
		vector<int>box;
		for(int i=0;i<n;i++)
		{
			int x1,y1,x2,y2;
			cin>>x1>>y1>>x2>>y2;
			seg[i<<1].l=seg[i<<1|1].l=x1;
			seg[i<<1].r=seg[i<<1|1].r=x2;
			seg[i<<1].y=y1;
			seg[i<<1|1].y=y2;
			seg[i<<1].flag=1;
			seg[i<<1|1].flag=-1;
			box.push_back(x1);
			box.push_back(x2);
		}
		sort(box.begin(),box.end());
		box.erase(unique(box.begin(),box.end()),box.end());
		for(int i=0;i<box.size();i++)
			hs[i+1]=box[i];
		n*=2;
		sort(seg,seg+n);
		int ans=0,p=0;
		create(1,box.size(),1);
		for(int i=0;i<n;i++)
		{
			int l=1+lower_bound(box.begin(),box.end(),seg[i].l)-box.begin();
			int r=1+lower_bound(box.begin(),box.end(),seg[i].r)-box.begin();
			update(l,r,1,seg[i].flag);
			ans+=abs(tree[1].val-p);
			p=tree[1].val;
			if(i!=n-1)
				ans+=(seg[i+1].y-seg[i].y)*tree[1].cnt*2;
		}
		printf("%d\n",ans);
	}
}

时间: 2024-10-18 18:05:40

hdu1828 Picture的相关文章

hdu1828 Picture(线段树+离散化+扫描线)两种方法

C - Picture Time Limit:2000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Description A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical or

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,就是给出图形中间的小矩

hdu1828 Picture (线段树:扫描线周长)

依然是扫描线,只不过是求所有矩形覆盖之后形成的图形的周长. 容易发现,扫描线中的某一条横边对答案的贡献. 其实就是 加上/去掉这条边之前的答案 和 加上/去掉这条边之后的答案 之差的绝对值 然后横着竖着都做一遍就行了 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define N 10010 5 #define ll long long 6 using namespace std;

线段树题目总结

一.单点更新 1.hdu1166 敌兵布阵:有N个兵营,每个兵营都给出了人数ai(下标从1开始),有四种命令,(1)"Addij",表示第i个营地增加j人.(2)"Sub i j",表示第i个营地减少j人.(3)"Query ij",查询第i个营地到第j个营地的总人数.(4)"End",表示命令结束.解题报告Here. 2.hdu1754 I Hate It:给你N个数,M个操作,操作分两类.(1)"QAB"

数据结构---线段树

线段树 转载请注明出处,谢谢!http://blog.csdn.net/metalseed/article/details/8039326  持续更新中···   一:线段树基本概念 1:概述 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)! 性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树

(转载)线段树模板(来自胡浩大牛)

http://www.notonlysuccess.com/(今天看二叉树,想回来看看,发现大牛博客进不去...) 如果要学,就要好好学.我copy的,如有错,请看http://www.cnblogs.com/Mu-Tou/archive/2011/08/11/2134427.html [完全版]线段树 很早前写的那篇线段树专辑至今一直是本博客阅读点击量最大的一片文章,当时觉得挺自豪的,还去pku打广告,但是现在我自己都不太好意思去看那篇文章了,觉得当时的代码风格实在是太丑了,很多线段树的初学者

线段树总结 (转载 里面有扫描线类 还有NotOnlySuccess线段树大神的地址)

转载自:http://blog.csdn.net/shiqi_614/article/details/8228102 之前做了些线段树相关的题目,开学一段时间后,想着把它整理下,完成了大牛NotOnlySuccess的博文“完全版线段树”里的大部分题目,其博文地址Here,然后也加入了自己做过的一些题目.整理时,更新了之前的代码风格,不过旧的代码仍然保留着. 同样分成四类,不好归到前四类的都分到了其他.树状数组能做,线段树都能做(如果是内存限制例外),所以也有些树状数组的题目,会标示出来,并且放

线段树——转

  一:线段树基本概念 1:概述 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)! 性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树需要的空间为数组大小的四倍 2:基本操作(demo用的是查询区间最小值) 线段树的主要操作有: (1):线段树的构造 void build(int node,

线段树(转)

线段树   转载请注明出处,谢谢!http://blog.csdn.net/metalseed/article/details/8039326  持续更新中···   一:线段树基本概念 1:概述 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)! 性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线