题目链接

题意 

多个矩形重叠在一起,求出轮廓线的长度。

分析 

把矩形分成横线和竖线来处理。现在分析横线的,竖线同理。矩形的坐标都是整数,且范围不大,故此题不需要离散化。从下往上扫描横线,每遇到一条横线,就计算长度,矩形的下边标为1,上边标为-1。具体计算方法是此次区间的总覆盖长度与上次区间长度相比,若没有变化,则说明新加入的横线是重叠的。故每次计算的答案便是两者之差的绝对值。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include <queue>
#include <vector>
#include<bitset>
#include<map>
#include<deque>
using namespace std;
typedef long long LL;
const int maxn = ;
const int mod = +;
typedef pair<int,int> pii;
#define X first
#define Y second
#define pb push_back
//#define mp make_pair
#define ms(a,b) memset(a,b,sizeof(a))
const int inf = 0x3f3f3f3f;
#define lson l,m,2*rt
#define rson m+1,r,2*rt+1 struct edge{
int l,r,h,f;
}ex[*maxn],ey[maxn*]; struct node{
int l,r,cover,len;
int mid(){
return (l+r)>>;
}
}tree[maxn*]; int cmp(edge a,edge b){
return a.h<b.h;
} void build(int l,int r,int rt){
tree[rt].l=l,tree[rt].r=r;
tree[rt].len=tree[rt].cover=;
if(l+==r) return;
int mid = tree[rt].mid();
build(l,mid,rt<<);
build(mid,r,rt<<|);
} void push_up(int rt){
if(tree[rt].cover){
tree[rt].len=tree[rt].r-tree[rt].l;
}else if(tree[rt].l+==tree[rt].r){
tree[rt].len=;
}else{
tree[rt].len=tree[rt<<].len+tree[rt<<|].len;
}
return;
} void update(edge e,int rt){
if(tree[rt].l==e.l&&tree[rt].r==e.r){
tree[rt].cover+=e.f;
push_up(rt);
return;
}
int m=tree[rt].mid();
if(e.r<=m) update(e,rt<<);
else if(e.l>=m) update(e,rt<<|);
else{
edge temp = e;
temp.r=m;
update(temp,rt<<);
temp = e;
temp.l=m;
update(temp,rt<<|);
}
push_up(rt);
}
int ans;
void work(int l,int r,edge seg[],int n){
build(l,r,);
int prelen=;
for(int i=;i<n;i++){
update(seg[i],);
ans += abs(tree[].len-prelen);
prelen=tree[].len;
}
} int main(){
int n,x1,x2,y1,y2;
while(~scanf("%d",&n)){
if(n==){
puts("");
continue;
} int maxx,maxy,minx,miny;
maxx=maxy=-inf,minx=miny=inf;
int cnt=;
for(int i=;i<n;i++){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
//横向
ex[cnt].l=ex[cnt+].l=x1,
ex[cnt].r=ex[cnt+].r=x2,
ex[cnt].h=y1,ex[cnt+].h=y2,
ex[cnt].f=,ex[cnt+].f=-; ey[cnt].l=ey[cnt+].l=y1,
ey[cnt].r=ey[cnt+].r=y2,
ey[cnt].h=x1,ey[cnt+].h=x2,
ey[cnt].f=,ey[cnt+].f=-;
cnt+=; maxx=max(maxx,max(x1,x2));
minx=min(minx,min(x1,x2));
miny=min(miny,min(y1,y2));
maxy=max(maxy,max(y1,y2));
} sort(ex,ex+cnt,cmp);
sort(ey,ey+cnt,cmp);
ans=;
work(minx,maxx,ex,cnt);
work(miny,maxy,ey,cnt);
printf("%d\n",ans);
}
return ;
}

还有一种更好的做好,参见http://www.cnblogs.com/scau20110726/archive/2013/04/13/3018687.html

同时计算横线和竖线

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 5010
#define MAX 10100
#define lch(i) ((i)<<1)
#define rch(i) ((i)<<1|1) struct segment{
int l,r,h,v;
}s[*N];
struct node{
int l,r,lp,rp,cnt,len,num;
int mid()
{ return (l+r)>>; }
}t[*MAX*]; int cmp(struct segment p ,struct segment q)
{
return p.h<q.h;
} void build(int l ,int r, int rt)
{
t[rt].l=l; t[rt].r=r;
t[rt].cnt=t[rt].len=;
t[rt].lp=t[rt].rp=t[rt].num=;
if(l==r) return ;
int mid=t[rt].mid();
build(l,mid,lch(rt));
build(mid+,r,rch(rt));
} void cal(int rt)
{
if(t[rt].cnt)
{
t[rt].len=t[rt].r-t[rt].l+;
t[rt].lp=t[rt].rp=;
t[rt].num=;
}
else if(t[rt].l == t[rt].r) //叶子
{
t[rt].len=;
t[rt].lp=t[rt].rp=;
t[rt].num=;
}
else
{
t[rt].len=t[lch(rt)].len+t[rch(rt)].len;
t[rt].lp=t[lch(rt)].lp;
t[rt].rp=t[rch(rt)].rp;
t[rt].num=t[lch(rt)].num + t[rch(rt)].num - (t[lch(rt)].rp&t[rch(rt)].lp);
}
} void updata(int l ,int r ,int v ,int rt)
{
if(t[rt].l==l && t[rt].r==r) //目标区间
{
t[rt].cnt += v;
cal(rt);
return ;
}
int mid=t[rt].mid();
if(r<=mid) updata(l,r,v,lch(rt));
else if(l>mid) updata(l,r,v,rch(rt));
else
{
updata(l,mid,v,lch(rt));
updata(mid+,r,v,rch(rt));
}
cal(rt);
} int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
if(n==)
{ puts(""); continue; }
int i,maxx,minx,m;
for(i=,m=,maxx=-MAX,minx=MAX; i<n; i++,m+=)
{
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
maxx=max(maxx,x2);
minx=min(minx,x1);
s[m].l=x1; s[m].r=x2; s[m].h=y1; s[m].v=;
s[m+].l=x1; s[m+].r=x2; s[m+].h=y2; s[m+].v=-;
}
sort(s,s+m,cmp);
build(minx,maxx-,);
int res= , prelen=;
s[m]=s[m+]; //每次处理循环的最后一次
for(int i=; i<m; i++)
{
updata(s[i].l,s[i].r-,s[i].v,);
res += abs(t[].len-prelen); //计算横线部分
res += (s[i+].h-s[i].h)*(*t[].num); //计算竖线部分
prelen=t[].len;
}
printf("%d\n",res);
}
return ;
}

HDU - 1828 Picture的更多相关文章

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

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

  2. HDU 1828 Picture(线段树扫描线求周长)

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

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

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

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

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

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

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

  6. 51nod 1206 && hdu 1828 Picture (扫描线+离散化+线段树 矩阵周长并)

    1206 Picture  题目来源: IOI 1998 基准时间限制:2 秒 空间限制:131072 KB 分值: 160 难度:6级算法题  收藏  关注 给出平面上的N个矩形(矩形的边平行于X轴 ...

  7. hdu 1828 Picture 切割线求周长

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

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

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

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

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

  10. (中等) HDU 1828 Picture,扫描线。

    Problem Description A number of rectangular posters, photographs and other pictures of the same shap ...

随机推荐

  1. Maven 3.3全局配置

    Maven采用全局配置的方案: <?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to ...

  2. 传输层中的协议 TCP & UDP

    面向连接的TCP协议 “面向连接”就是在正式通信前必须要与对方建立起连接.比如你给别人打电话,必须等线路接通了.对方拿起话筒才能相互通话.TCP(Transmission Control Protoc ...

  3. 软件工程_5th weeks

    从周五开始经历了清明小长假,周六.周日和周一都处于假期状态,因此对于上篇博客的评论回复的很迟,而这周的工作做的也不多. 1.爆打小组 4.5日站立会议 时间:2016.4.5 15:00-15:34 ...

  4. Windows server 2008 r2下载地址和激活破解方法

    Windows 7发布了服务器版本——Windows Server 2008 R2.同2008年1月发布的Windows Server 2008相比,Windows Server 2008 R2继续提 ...

  5. ImportError: cannot import name descriptor_pb2

    重新编译protobuf 下载地址:https://github.com/google/protobuf $cd /path/protobuf/python $python setup.py buil ...

  6. codeforces659B

    Qualifying Contest CodeForces - 659B Very soon Berland will hold a School Team Programming Olympiad. ...

  7. java常见面试题及答案

    java常见面试题及答案 来源 https://blog.csdn.net/hsk256/article/details/49052293 来源 https://blog.csdn.net/hsk25 ...

  8. 任意目录下启动tomcat

    DOS中启动tomcat 1.将tomcat的bin目录添加到Path变量中 2.添加catalina_home变量 3.命令行输入catalina run ojbk

  9. 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)

    线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...

  10. 自学Linux Shell12.5-while、until命令

    点击返回 自学Linux命令行与Shell脚本之路 12.5-while.until命令 until 循环与 while 循环在处理方式上刚好相反. while循环用于不断执行一系列命令,也用于从输入 ...