题目背景

墙上贴着许多形状相同的海报、照片。它们的边都是水平和垂直的。每个矩形图片可能部分或全部的覆盖了其他图片。所有矩形合并后的边长称为周长。

题目描述

编写一个程序计算周长。

如图1所示7个矩形。

如图2所示,所有矩形的边界。所有矩形顶点的坐标都是整数。

解析

首先想到模拟,这题数据小,直接暴力扫转折点,统计周长的增量就得了。

其实最优解就是这么做的。

TAG里有扫描线,咱就用扫描线吧。

简单来说,还是扫描线同样的思路,做线段覆盖(具体实现可以百度,我懒得写了)。入边权值为+1,出边权值为-1,从下到上扫一遍,从左到右扫一遍,在遇到入边时,统计当前扫描线与上一条之间覆盖线段长度的增量,这个增量具体来说就是做差。

简单的正确性证明:对于上述每一个增量,其都是由入边造成的,那么这个增量最终都会被出边抵消。因此若我们只统计入边造成的增量,其两倍就是总矩形周长。其实非常好想。

参考代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 20010
#define MOD 2520
#define E 1e-12
using namespace std;
inline int read()
{
int f=1,x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
struct node{
int l,r,h,v;
bool operator<(const node &a)const{
if(a.h==h) return a.v<v;
return a.h>h;
}
}h[N],l[N];
struct tree{
int l,r;
int cnt,dat;
}t[N<<2];
int n,hh[N],hl[N],cmd;
inline void pushup(int p)//线段覆盖
{
if(t[p].cnt){
if(cmd==1) t[p].dat=hh[t[p].r+1]-hh[t[p].l];
else t[p].dat=hl[t[p].r+1]-hl[t[p].l];
}
else if(t[p].l==t[p].r) t[p].dat=0;
else t[p].dat=t[p<<1].dat+t[p<<1|1].dat;
}
inline void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;
t[p].cnt=t[p].dat=0;
if(l==r) return;
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
}
inline void change(int p,int l,int r,int val)
{
if(l<=t[p].l&&t[p].r<=r){
t[p].cnt+=val;
pushup(p);
return;
}
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid) change(p<<1,l,r,val);
if(r>mid) change(p<<1|1,l,r,val);
pushup(p);
}
int main()
{
n=read();
int cnth=0,cntl=0,th=0,tl=0;
for(int i=1;i<=n;++i){
int x1,x2,y1,y2;
x1=read(),y1=read(),x2=read(),y2=read();
h[++cnth].l=x1,h[cnth].r=x2,h[cnth].h=y1,h[cnth].v=1;
l[++cntl].l=y1,l[cntl].r=y2,l[cntl].h=x1,l[cntl].v=1;
h[++cnth].l=x1,h[cnth].r=x2,h[cnth].h=y2,h[cnth].v=-1;
l[++cntl].l=y1,l[cntl].r=y2,l[cntl].h=x2,l[cntl].v=-1;
hh[++th]=x1,hh[++th]=x2;
hl[++tl]=y1,hl[++tl]=y2;
}
sort(hh+1,hh+th+1);sort(hl+1,hl+tl+1);
sort(h+1,h+cnth+1);sort(l+1,l+cntl+1);
unique(hh+1,hh+th+1);unique(hl+1,hl+tl+1);
int ans=0,tmp=0;
build(1,1,cnth);
cmd=1;
for(int i=1;i<=cnth;++i){
int x,y;
x=lower_bound(hh+1,hh+th+1,h[i].l)-hh;
y=lower_bound(hh+1,hh+th+1,h[i].r)-hh-1;
change(1,x,y,h[i].v);
if(h[i].v==1)ans+=t[1].dat-tmp;
tmp=t[1].dat;
}
build(1,1,cntl);
cmd=2,tmp=0;
for(int i=1;i<=cntl;++i){
int x,y;
x=lower_bound(hl+1,hl+tl+1,l[i].l)-hl;
y=lower_bound(hl+1,hl+tl+1,l[i].r)-hl-1;
change(1,x,y,l[i].v);
if(l[i].v==1)ans+=t[1].dat-tmp;
tmp=t[1].dat;
}
ans<<=1;
cout<<ans<<endl;
return 0;
}

P1856 [USACO5.5]矩形周长Picture[扫描线]的更多相关文章

  1. luogu P1856 [USACO5.5]矩形周长Picture 扫描线 + 线段树

    Code: #include<bits/stdc++.h> #define maxn 200007 #define inf 100005 using namespace std; void ...

  2. P1856 [USACO5.5]矩形周长Picture

    P1856 [USACO5.5]矩形周长Picture $len$            $sum$              $num$             $flag\_l$ $flage\_ ...

  3. 洛谷P1856 [USACO5.5]矩形周长Picture

    题目背景 墙上贴着许多形状相同的海报.照片.它们的边都是水平和垂直的.每个矩形图片可能部分或全部的覆盖了其他图片.所有矩形合并后的边长称为周长. 题目描述 编写一个程序计算周长. 如图1所示7个矩形. ...

  4. Luogu P1856 [USACO5.5]矩形周长Picture

    线段树+扫描线 经典的扫描线问题 首先将一个矩形看作由竖着的两条边和横着的两条边构成 那分成两次考虑,一次考虑竖边,一次考虑横边 首先考虑横边 如图两个矩形,现将横边擦去,留下竖边,将平面划分成3个区 ...

  5. [题解]P1856 [USACO5.5]矩形周长Picture

    Loli 考试的题目之一 题目地址 \(N^2\)做法 #include <cstdio> #include <cstring> #define re register #de ...

  6. luogu1856 [USACO5.5]矩形周长Picture

    看到一坨矩形就要想到扫描线.(poj atantis) 我们把横边竖边分开计算,因为横边竖边其实没有区别,以下论述全为考虑竖边的. 怎样统计一个竖边对答案的贡献呢?答:把这个竖边加入线段树,当前的总覆 ...

  7. [USACO5.5] 矩形周长Picture

    https://www.luogu.org/problemnew/show/P1856 1.每个矩形由两条横向边和两条纵向边组成. 2.对于横向边,按纵坐标排序.设当前讨论的边为 A [s , t] ...

  8. Luogu1856 [USACO5.5]矩形周长Picture (线段树扫描线)

    对于横轴,加上与上一次扫描的差值:对于竖轴,加上高度差与区间内不相交线段\(*2\)的积: 难点在pushdown,注意维护覆盖关系.再就注意负数 #include <iostream> ...

  9. 「USACO5.5」矩形周长Picture

    题目描述 墙上贴着许多形状相同的海报.照片.它们的边都是水平和垂直的.每个矩形图片可能部分或全部的覆盖了其他图片.所有矩形合并后的边长称为周长. 编写一个程序计算周长. 如图1所示7个矩形. 如图2所 ...

随机推荐

  1. 使用 Nginx 阻止恶意 IP 访问

    找到具有明显特征的访问记录,比如: /Dec/::: +] "-" "Ouija_x.86/2.0" "-" 也许是某个开源框架的漏洞,执行 ...

  2. Difference between java.lang.RuntimeException and java.lang.Exception

    In Java, there are two types of exceptions: checked exceptions and un-checked exceptions. A checked ...

  3. zabbix 后台数据库清除数据

    alerts 表 problem 表 escalations 表 events 表  event_recovery表 对 这些表进行清除 防止不停发送邮件 -- alerts table rebuil ...

  4. activiti学习6:启动流程后动态获取流程图

    目录 activiti学习6:启动流程后动态获取流程图 一.绘图原理 二.根据流程定义id绘图 三.根据流程实例id绘图 3.1 基本原理 3.2 当前节点的获取 3.3 走过的节点的获取 3.4 绘 ...

  5. mysql慢查询及查询优化

    mysql默认是没有开启慢查询的 1 查看慢查询的配置状态 show variables like 'slow_query%'; slow_query_log 慢查询开启状态 slow_query_l ...

  6. Vue框架(一)——Vue导读、Vue实例(挂载点el、数据data、过滤器filters)、Vue指令(文本指令v-text、事件指令v-on、属性指令v-bind、表单指令v-model)

    Vue导读 1.Vue框架 vue是可以独立完成前后端分离式web项目的js框架 三大主流框架之一:Angular.React.Vue vue:结合其他框架优点.轻量级.中文API.数据驱动.双向绑定 ...

  7. kibana内存设置

    kibana是一个基于NodeJS的单页web应用.而NodeJS则是基于Chrome V8引擎的.V8引擎对于内存的使用是有限制的,默认情况下,64位系统下约为1.4GB,32位系统下约为0.7GB ...

  8. ABP 结合 MongoDB 集成依赖注入

    1.我们再ABP项目添加一个.NET Core类库  类库名自定定义, 我这里定义为 TexHong_EMWX.MongoDb 添加NuGet包. ABP mongocsharpdriver 添加 A ...

  9. mysql-数据备份与存储过程

    目录 修改隔离级别 存储过程 什么是存储过程 用来干什么 三种数据处理方式 备份与恢复 修改隔离级别 修改全局的 set global transaction isolation level read ...

  10. IOWebSocketChannel.connect handle errors

    https://github.com/dart-lang/web_socket_channel/issues/38 yes, my workaround is to create a WebSocke ...