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

思路:求纵向边要维护重叠次数大于0的纵向长度。用上一次的node[1].m减去当前的node[1].m的绝对值。求横向边要维护每一次更新之后须要加上去的边数。

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std; struct L{
int val;//1 左边。-1 右边
int x,y1,y2;
}l[10000]; struct N{
int l,r,n,m;//n记录节点相应的有效横向边数量,m记录纵向长度
int cnt;//重叠情况
bool lc,rc;
}node[40000]; int tempy[10000]; bool cmp(struct L a,struct L b)
{
if(a.x==b.x) return a.val>b.val; return a.x<b.x;
} void build(int idx,int s,int e)
{
node[idx].cnt=0;
node[idx].m=0;
node[idx].lc=node[idx].rc=0;
node[idx].l=tempy[s-1];
node[idx].r=tempy[e-1]; if(s+1!=e)
{
int mid=(s+e)>>1; build(idx<<1,s,mid);
build(idx<<1|1,mid,e);
}
} void len(int idx,int s,int e)
{
if(node[idx].cnt>0)
{
node[idx].m=node[idx].r-node[idx].l;
node[idx].n=2;//相应两条边
node[idx].lc=node[idx].rc=1;
}
else
{
if(s+1!=e)
{
int mid=(s+e)>>1; node[idx].m=node[idx<<1].m+node[idx<<1|1].m;
node[idx].n=node[idx<<1].n+node[idx<<1|1].n;
node[idx].lc=node[idx<<1].lc;
node[idx].rc=node[idx<<1|1].rc;
if(node[idx<<1].rc && node[idx<<1|1].lc) node[idx].n-=2;//假设左右儿子是连着的。就要减去多计算的两条边
}
else
{
node[idx].m=0;
node[idx].n=0;
node[idx].lc=node[idx].rc=0;
}
}
} void update(int idx,int s,int e,struct L line)
{
if(node[idx].l==line.y1 && node[idx].r==line.y2)
{
node[idx].cnt+=line.val;
len(idx,s,e);
return;
} if(s+1!=e)
{
int mid=(s+e)>>1; if(line.y2<=node[idx<<1].r) update(idx<<1,s,mid,line);
else if(line.y1>=node[idx<<1|1].l) update(idx<<1|1,mid,e,line);
else
{
int temp=line.y2; line.y2=node[idx<<1].r;
update(idx<<1,s,mid,line);
line.y2=temp; line.y1=node[idx<<1|1].l;
update(idx<<1|1,mid,e,line);
} } len(idx,s,e);
} int main()
{
int T,n,i,t;
int x1,x2,y1,y2; while(~scanf("%d",&n))
{
for(i=0;i<n;i++)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2); tempy[i*2]=y1;
tempy[i*2+1]=y2; l[i*2].val=1;
l[i*2].x=x1;
l[i*2].y1=y1;
l[i*2].y2=y2; l[i*2+1].val=-1;
l[i*2+1].x=x2;
l[i*2+1].y1=y1;
l[i*2+1].y2=y2;
} sort(tempy,tempy+n*2);
sort(l,l+n*2,cmp); t=unique(tempy,tempy+n*2)-tempy;//去重 build(1,1,t); int ans=0,last=0; for(i=0;i<n*2;i++)
{
if(i) ans+=node[1].n*(l[i].x-l[i-1].x); update(1,1,t,l[i]); ans+=abs(node[1].m-last);
last=node[1].m;
} printf("%d\n",ans);
}
}

HDU-1828-Picture(线段树)的更多相关文章

  1. hdu 1828 Picture(线段树 || 普通hash标记)

    http://acm.hdu.edu.cn/showproblem.php?pid=1828 Picture Time Limit: 6000/2000 MS (Java/Others)    Mem ...

  2. POJ 1177/HDU 1828 picture 线段树+离散化+扫描线 轮廓周长计算

    求n个图矩形放下来,有的重合有些重合一部分有些没重合,求最后总的不规则图型的轮廓长度. 我的做法是对x进行一遍扫描线,再对y做一遍同样的扫描线,相加即可.因为最后的轮廓必定是由不重合的线段长度组成的, ...

  3. HDU 1828 Picture (线段树+扫描线)(周长并)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1828 给你n个矩形,让你求出总的周长. 类似面积并,面积并是扫描一次,周长并是扫描了两次,x轴一次,y ...

  4. hdu 1828 Picture(线段树轮廓线)

    Picture Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

  5. HDU 1828 Picture (线段树:扫描线周长)

    依然是扫描线,只不过是求所有矩形覆盖之后形成的图形的周长. 容易发现,扫描线中的某一条横边对答案的贡献. 其实就是 加上/去掉这条边之前的答案 和 加上/去掉这条边之后的答案 之差的绝对值 然后横着竖 ...

  6. HDU 1828 Picture(长方形的周长和)

    HDU 1828 Picture 题目链接 题意:给定n个矩形,输出矩形周长并 思路:利用线段树去维护,分别从4个方向扫一次,每次多一段的时候,就查询该段未被覆盖的区间长度,然后周长就加上这个长度,4 ...

  7. hdu 4031 attack 线段树区间更新

    Attack Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Subm ...

  8. hdu 4288 离线线段树+间隔求和

    Coder Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Su ...

  9. hdu 3016 dp+线段树

    Man Down Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  10. HDU 1828“Picture”(线段树+扫描线求矩形周长并)

    传送门 •参考资料 [1]:算法总结:[线段树+扫描线]&矩形覆盖求面积/周长问题(HDU 1542/HDU 1828) •题意 给你 n 个矩形,求矩形并的周长: •题解1(两次扫描线) 周 ...

随机推荐

  1. 初学者最易懂的git教程在这里!

    一.git简介: Linux创建了Linux,但是Linux的发展壮大是由世界各地的热心志愿者参与编写的?那么那么多份的代码是怎么合并的呢?之前是在2002年以前,世界各地的志愿者把源代码文件通过di ...

  2. Minix3信号处理分析

    进程的信号处理的相关结构 PM中存放着所有进程的进程描述符,在一个进程描述符中,有一个指针,指向一个sigaction结构二维数组中的一项,表示这个进程所有信号的操作.一个sigaction结构包含信 ...

  3. 《Linux命令行与shell脚本编程大全》 第六章环境变量

    很多程序和脚本都通过环境变量来获取系统信息.存储临时数据和配置信息. 6.1 什么是环境变量: bash shell用一个叫环境变量(environment variable)的特性来存储有关shel ...

  4. 关于双11过后MATLAB许可过期问题的解决方案

    在距离双11还有2个月之前,matlab会提示:Your MATLAB license will expire in 50 days --------------------------------- ...

  5. [ASP.NET Core 2.0 前方速报]Core 2.0.3 已经支持引用第三方程序集了

    发现问题 在将 FineUIMvc(支持ASP.NET MVC 5.2.3)升级到 ASP.NET Core 2.0 的过程中,我们发现一个奇怪的现象: 通过项目引用 FineUICore 工程一切正 ...

  6. Python的__main__.py用法

    [背景] 在看flower的时候看到__main__.py文件,不知道具体做什么用? 故先进行测试看看. [测试代码] 测试代码目录结构如下: . `-- test |-- __init__.py | ...

  7. Storm入门之第二章

    1.准备开始 本章创建一个Storm工程和第一个Storm拓扑结构. 需要提供JER版本在1.6以上,下载地址http://www.java .com/downloads/. 2.操作模式 Storm ...

  8. 使用PHP文件锁写一个多个请求同时并发写入一个文件,要求不脏读、数据不丢失

    使用PHP文件锁写一个多个请求同时并发写入一个文件,要求不脏读.数据不丢失. //并发文件操作 function filehandle($filename,$data){ $start = 0; $e ...

  9. python 自动拉起进程脚本

    cat /usr/local/ssdb/moniter_ssdb.py #!/usr/bin/env python import os import sys import commands #ssdb ...

  10. DIV居中的经典方法

    1. 实现DIV水平居中 设置DIV的宽高,使用margin设置边距0 auto,CSS自动算出左右边距,使得DIV居中. 1 div{ 2 width: 100px; 3 height: 100px ...