题目背景

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

题目描述

编写一个程序计算周长。

如图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. Matlab 非线性规划问题模型代码

    非线性规划问题的基本内容 非线性规划解决的是自变量在一定的非线性约束或线性约束组合条件下,使得非线性目标函数求得最大值或者最小值的问题. 当目标函数为最小值时,上述问题可以写成如下形式: \[ \mi ...

  2. Ribbon和Nignx的区别

    Ribbon属于客户端负载均衡:在调用接口的时候,会通过服务别名到eureka上获取服务的信息列表,缓存到jvm本地,在本地采用RPC远程调用技术去调用接口,实现负载均衡.可以设置调用的规则是请求总数 ...

  3. [转帖]期待下一个十年|CIS 2019温馨回顾(附PPT下载)

    期待下一个十年|CIS 2019温馨回顾(附PPT下载) https://www.freebuf.com/fevents/222236.html shidongqi2019-12-06共26587人围 ...

  4. C++中几种字符串表示方法

    最近学习C++时,被几种字符串搞的有点乱,这里记录一下. c++中有两种风格字符串,分别是: C++风格字符串 C风格字符串 它们各自的声明方式如下: void main(){ string a = ...

  5. 【Python爬虫案例学习】Python爬取淘宝店铺和评论

    安装开发需要的一些库 (1) 安装mysql 的驱动:在Windows上按win+r输入cmd打开命令行,输入命令pip install pymysql,回车即可. (2) 安装自动化测试的驱动sel ...

  6. go 指针 通过指针修改int类型的值

    指针的定义 :var p *int 取指针的值 :*p ------------------------------------------------------------------------ ...

  7. 下载并使用MNIST数据集

    TensorFlow提供了一个库,可以直接用来自动下载与安装MNIST. MNIST里包含3个数据集:第一个是训练数据集(mnist.train.images),另外两个分别是测试数据集(mnist. ...

  8. KEPServerEX 6 配置连接 Allen-Bradley MicroLogix 1400

    =============================================== 2019/7/28_第1次修改                       ccb_warlock == ...

  9. 【leetcode-135,62,63 动态规划】分发糖果 ,不同路径

    分发糖果 老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分. 你需要按照以下要求,帮助老师给这些孩子分发糖果: 每个孩子至少分配到 1 个糖果. 相邻的孩 ...

  10. angular复习笔记4-模板

    Angular复习笔记4-模板 简介 模板是一种自定义的标准化页面,通过模板和模板中的数据结合,可以生成各种各样的网页.在Angular中,模板的默认语言是HTML,几乎所有的HTML语法在模板中都是 ...