【poj1177】 Picture
http://poj.org/problem?id=1177 (题目链接)
题意
求矩形周长并。
Solution
转自:http://www.cnblogs.com/Booble/archive/2010/10/10/1847163.html
先看图:
为了解决这个问题 我们先把一坨一坨的矩形 进行矩形切割:
我们考虑周长由哪些部分构成
其中,红线是需要统计入周长的竖边,绿线是需要统计入周长的横边
我们称两条蓝线之间的部分为统计区间
我们需要依次统计从左到右的统计区间内的需要计数的矩形边,累加
形象地讲,就是用一根扫描线,从左到右依次扫描
具体实现就是依次遍历那些蓝线然后,累加每个区间的统计结果
我们任取2个统计区间进行详细讨论,放大前2个统计区间部分
考虑为什么同样是矩形边,红边需要统计而棕色的边不需要统计
我们发现深红色的边包含在第一个矩形内部,也就是夹在第一个矩形两条红边之间
继续分析,我们可以知道,横边也是这样
深蓝色边加在统计区间内的两条绿色边之间,属于矩形内部,不需要统计
那么,如何判定是否是红边或绿边呢?
我们在扫描线上投下当前经过扫描线矩形的投影
红边必然造成投影的变化,绿边必然在投影上线段的端点处
没有造成投影变化的竖边,肯定在投影内部,也就是在还未扫描完的矩形内部
不在投影线段段端点处的横边 也会夹在在投影线段端点处的两个矩形边内
于是,我们将绿边的长度=统计区间宽*投影连续段数*2
再与红边的长度=与上一个区间投影的差求和,即得到当前区间的统计值,再累加即可
考虑怎么统计答案,我们采用线段树:
先将一个矩形一分为二,分别记录下左竖边,右竖边,差分。将竖边按照左端点排序,扫描线从左到右扫描,依次将竖边所在的区间加入线段树,统计答案。
用线段树记录下扫描线上的投影的情况
当扫描线碰到举行左边的时候就插入这个线段,碰到矩形右边就删除这个线段(差分)
我们还要重新规划在线段树上的域:覆盖次数cov[],连续段数num[],长度len[](即被覆盖的总长度)
这几个域需要我们实时维护,更需增加维护的域ls[],rs[]表示左右端点是否被覆盖
于是问题至此就差不多解决了,注意我们线段树上记录的是区间而不是端点,这样更方便我们统计答案。
细节
左右下标。
代码
// poj1177
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=20010;
struct tree {int l,r,len,ls,rs,num,cov;}tr[maxn<<2];
struct data {int x,l,r,val;}a[maxn];
int n; void build(int k,int s,int t) {
tr[k].l=s;tr[k].r=t;
if (s==t) return;
int mid=(s+t)>>1;
build(k<<1,s,mid);
build(k<<1|1,mid+1,t);
}
void merge(int k) {
int l=tr[k].l,r=tr[k].r;
if (tr[k].cov) {
tr[k].ls=tr[k].rs=1;
tr[k].num=2;
tr[k].len=r-l+1;
}
else if (l==r) tr[k].ls=tr[k].rs=tr[k].len=tr[k].num=0;
else {
tr[k].num=tr[k<<1].num+tr[k<<1|1].num;
tr[k].len=tr[k<<1].len+tr[k<<1|1].len;
tr[k].ls=tr[k<<1].ls;tr[k].rs=tr[k<<1|1].rs;
if (tr[k<<1].rs && tr[k<<1|1].ls) tr[k].num-=2;
}
}
void update(int k,int s,int t,int val) {
int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
if (s<=l && t>=r) {tr[k].cov+=val;merge(k);return;}
if (s<=mid) update(k<<1,s,t,val);
if (t>mid) update(k<<1|1,s,t,val);
merge(k);
}
bool cmpx(data a,data b) {
return a.x<b.x;
}
int main() {
scanf("%d",&n);
int m=0,l=inf,r=-inf;
for (int x1,x2,y1,y2,i=1;i<=n;i++) {
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
l=min(l,y1);r=max(r,y2);
a[++m]=(data){x1,y1,y2,1};a[++m]=(data){x2,y1,y2,-1};
}
n=m;
build(1,l,r-1);
sort(a+1,a+1+n,cmpx);
int ans=0;
for (int i=1;i<=n;i++) {
int tmp=tr[1].len;
if (i!=1) ans+=tr[1].num*(a[i].x-a[i-1].x);
update(1,a[i].l,a[i].r-1,a[i].val);
ans+=abs(tr[1].len-tmp);
}
printf("%d",ans);
return 0;
}
【poj1177】 Picture的更多相关文章
- 【HDOJ1828&&POJ1177】Picture(线段树,扫描线)
题意:给定n个矩形,求他们的并的周长 n<=5e3,abs(x[i])<=1e4 思路:From https://www.cnblogs.com/kuangbin/archive/2013 ...
- 【MFC】picture控件 两种有细微差别的动态加载图片方法
摘自:http://www.jizhuomi.com/software/193.html VS2010/MFC编程入门之二十七(常用控件:图片控件Picture Control) 分类标签: 编程入门 ...
- 【IOI1998】Picture(扫描线+线段树)
问题来源:IOI1998 D2T1 题意:就是在一个平面内给出n个矩形,叫你计算将这些矩形合并以后,新图形的周长. 例如: 上图是原本的矩形们 ---------->合并后的图形 解题思路:拿一 ...
- 【HDU 1828】 Picture (矩阵周长并,线段树,扫描法)
[题目] Picture Problem Description A number of rectangular posters, photographs and other pictures of ...
- 【题解】POJ2279 Mr.Young′s Picture Permutations dp
[题解]POJ2279 Mr.Young′s Picture Permutations dp 钦定从小往大放,然后直接dp. \(dp(t1,t2,t3,t4,t5)\)代表每一行多少人,判断边界就能 ...
- 【IOI 1998】 Picture
[题目链接] 点击打开链接 [算法] 线段树扫描线求周长并 [代码] #include <algorithm> #include <bitset> #include <c ...
- 【49.23%】【hdu 1828】Picture
Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s) ...
- 【转】ACM训练计划
[转] POJ推荐50题以及ACM训练方案 -- : 转载自 wade_wang 最终编辑 000lzl POJ 推荐50题 第一类 动态规划(至少6题, 和 必做) 和 (可贪心) (稍难) 第二类 ...
- 【HOW】如何配置SharePoint传入/传出电子邮件设置
SharePoint 2010的传入和传出邮件配置选项都较简单,但由于需要DNS及Exchange等服务器互相配合,所以要正确配置并不容易. 在微软的官方文档中详细说明了配置步骤:配置传入电子邮件:h ...
随机推荐
- 使用Jquery向一个空白网页动态创建一个iframe,及嵌入页面,和向嵌入页面传参
[csharp] view plaincopyprint?using Microsoft.VisualBasic; using System; using System.Collections; us ...
- sqlserver 通用分页存储过程
来源:http://www.jb51.net/article/19936.htm CREATE PROCEDURE commonPagination ), --要显示的列名,用逗号隔开 ), --要查 ...
- (转)c# 解析JSON的几种办法
来自:http://blog.csdn.net/gaofang2009/article/details/6073029 欲成为海洋大师,必知晓海中每一滴水的真名. 刚开始只是想找一个转换JSON数组的 ...
- 架设ftp反向代理服务器
因网络环境限制,需要从内网(不能直接连通外网)向外部的ftp上传.下载文件,只能在网关服务器上架设ftp反向代理(网关服务器可同时连通外网与内网,但是不允许内部应用部署在这台机器上). 试了几个方案: ...
- 浅谈设计模式--建造器模式(Builder Pattern)
建造器模式,是于创建带有大量参数的对象,并避免因参数数量多而产生的一些问题(如状态不一致-JavaBean的setter模式). 如果参数多且有些是必须初始化的,有些是不一定需要初始化的时候,创建对象 ...
- c++多重继承小结
如果一个类从两个不同的类里继承两个同名的成员,则需要在派生类中使用类限定符来区分他们. 即在从A和B派生出来的c类中使用a::Show()和B::Show()来区分从这两个类那里继承的show()方法 ...
- 迭代器模式的一种应用场景以及C#对于迭代器的内置支持
迭代器模式 先放上gof中对于迭代器模式的介绍镇楼 意图 提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示. 别名 游标(Cursor). 动机 一个聚合对象, 如列表(li ...
- 高仿Windows Phone QQ登录界面
给 TextBox文本框前添加图片 扩展PhoneTextBox:添加一个类"ExtentPhoneTextBox"继承 PhoneTextBox ,在"ExtentPh ...
- 7z压缩文件时排除指定的文件
分享一个7z压缩文件时排除指定文件类型的命令行,感觉很有用: 7z a -t7z d:\updateCRM.7z d:\updateCRM\*.* -r -x!*.log -x!*bak a:创建压缩 ...
- 转一篇关于Unity的PlayMaker
这篇文章转自http://va.lent.in/should-you-use-playmaker-in-production/ 此文作者大概深受其苦,吐槽了playmaker的多个蛋疼的地方,这其实说 ...