题目背景

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

题目描述

编写一个程序计算周长。

如图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. java学习摘抄笔记mybaits2

    mybatis第二天  高级映射 查询缓存 和spring整合 课程复习: mybatis是什么? mybatis是一人持久层框架,mybatis是一个不完全的ORM框架.sql语句需要程序员自己去编 ...

  2. 如何利用Docker构建基于DevOps的全自动CI

    来自用户的DevOps实践分享,分享从开发代码到生产环境部署的一条龙操作的实践及经验, 包含工具技术的选型及考量.私有代码库与私有镜像库的应用等. (一)容器服务的Rancher选型 1.为什么说是下 ...

  3. Mac多SSH Key配置

    多SSH key配置 工作的时候碰到SSH配置的问题,就是公司用的是gittea的仓库,而本人的github平常也要使用,这个时候就需要配置不同的SSH key了.将同一个公钥分配配置给github和 ...

  4. Linux用户查询、新增&删除

    1.查询用户tail -1 /etc/passwd 2.新增用户&用户组groupadd testgroup #组的添加useradd testuser #创建用户testuserpasswd ...

  5. 前端与算法 leetcode 189. 旋转数组

    目录 # 前端与算法 leetcode 189. 旋转数组 题目描述 概要 提示 解析 算法 # 前端与算法 leetcode 189. 旋转数组 题目描述 189. 旋转数组 概要 把他当做一到简单 ...

  6. pytest_用例a失败,跳过测试用例b和c并标记失败xfail

    前言 当用例a失败的时候,如果用例b和用例c都是依赖于第一个用例的结果,那可以直接跳过用例b和c的测试,直接给他标记失败xfail用到的场景,登录是第一个用例,登录之后的操作b是第二个用例,登录之后操 ...

  7. 对一次 redis 未授权写入攻击的分析以及学习

    前段时间自己使用 redis 开发的时候,搞了一个 docker ,然后直接开放连接没有密码,其实一开始我就知道会被黑产扫到然后给我种马,但是把因为也是测试服务,其实也没怎么上心,于是就放任自由了,结 ...

  8. IE浏览器 location.href 不跳转

    var url = "https://www.cnblogs.com/zing"; location.href = url; window.event.returnValue = ...

  9. C# 简单的定时器使用

    using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...

  10. EFCore自动迁移

    2019/05/14,EFCore 2.2.4 有两种方式: 使用Migrate()方法 if (DbContext.Database.GetPendingMigrations().Any()) { ...