[Arc063F] Snuke's Coloring 2

题目大意

给你一个网格图,一些点上有标记,求边长最大空白矩形。

试题分析

专门卡\(\log^2 n\)系列。

首先由题意我们可以找到答案的下界:\(\min(H,W)\times 2+2\)。

那么就是说这个矩形的周长如果要大于下界肯定会跨越中轴线\(H\)或\(W\),那么我们只需要在两边枚举即可。

这个东西看起来没什么用,我们姑且将其当作常数优化,但是在后面的讨论中它极大地简化了问题。

继续考虑传统扫描线的方向,那么看看当我们确定了任意一个边界的时候可以干什么。

假定这里枚举的是右边界,然后左边界又没有东西可以维护了,那就直接让线段树维护:枚举右边界到点\(i\),左边界为下标时的周长最大值。

现在就是扫描线的问题了,既然维护的是右边界和左边界,那么就肯定按照x轴从左向右扫。

对于上下界的部分,对于每个点维护两个单调栈,方向如下图。

但是这样一来的话就需要开主席树模拟单调栈,相当恶心,并且多了一个log。

怎么办呢?上面我们说过,这个矩形肯定会跨越中轴线,也就是说,我们只需要在中轴线上面维护一个,在下面维护一个单调栈就足够了。

于是,我们的矩形变成了这个样子:

那么下面就是考虑在单调栈进出的时候去更新线段树了,这里建议画一下图:

  • 我们枚举点并加入左边界的考虑部分,因为这个点相对于上一个点会向上移动,加入这个点的时候首先需要弹掉单调队列在它下面的点,然后要把编号在\({id_{stack_{top}}}\)和\({id_{stack_{last\space top}}}\)之间的这些点都减去\(y_i-y_{id_{stack_{top}}}\),因为需要将当前右边界转到下一个点上去。
  • 对于上面也是相同,只需要维护一个如图反着的单调队列即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
//#include<ctime>
//#include<cmath>
//#include<queue> using namespace std;
#define LL long long inline LL read(){
LL x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const LL INF = 2147483600;
const LL MAXN = 500010; struct data{
LL x,y;
}p[MAXN+1],a[MAXN+1],b[MAXN+1];
data make_data(LL xx,LL yy){
data a; a.x=xx; a.y=yy; return a;
}
LL N,W,H;
LL tag[MAXN<<2],tr[MAXN<<2];
bool cmp(data a,data b){
if(a.x!=b.x) return a.x<b.x;
return a.y<b.y;
}
inline void tage_lazy(LL rt){
if(!tag[rt]) return ;
tag[rt<<1]+=tag[rt]; tag[rt<<1|1]+=tag[rt];
tr[rt<<1]+=tag[rt]; tr[rt<<1|1]+=tag[rt];
tag[rt]=0;
return ;
}
inline void update(LL rt,LL l,LL r,LL L,LL R,LL k){
if(L>R) return ;
if(L<=l&&R>=r){tr[rt]+=k; tag[rt]+=k; return ;} tage_lazy(rt);
LL mid=(l+r)>>1; if(L<=mid) update(rt<<1,l,mid,L,R,k);
if(R>mid) update(rt<<1|1,mid+1,r,L,R,k);
tr[rt]=max(tr[rt<<1],tr[rt<<1|1]); return ;
} LL ans=0; inline void work(){
sort(p+1,p+N+1,cmp);
memset(tr,0,sizeof(tr));
memset(tag,0,sizeof(tag));
LL l=0,r=0;
for(LL i=1;i<=N;i++){
if(p[i].y<=(H>>1)){
LL lat=i-1;
while(l&&a[l].y<p[i].y){
update(1,1,N,a[l].x,lat,a[l].y-p[i].y);
lat=a[l].x-1; --l;
} if(lat!=i-1){
a[++l]=make_data(lat+1,p[i].y);
}
} else{
LL lat=i-1;
while(r&&b[r].y>p[i].y){
update(1,1,N,b[r].x,lat,p[i].y-b[r].y);
lat=b[r].x-1; --r;
} if(lat!=i-1){
b[++r]=make_data(lat+1,p[i].y);
}
} a[++l]=make_data(i,0);
b[++r]=make_data(i,H); update(1,1,N,i,i,H-p[i].x);
ans=max(ans,tr[1]+p[i+1].x);
} return ;
} int main(){
//freopen("a.in","r",stdin);
//freopen(".out","w",stdout);
W=read(),H=read(); N=read();
for(LL i=1;i<=N;i++){
p[i].x=read(),p[i].y=read();
} p[++N].x=0; p[N].y=0; p[++N].x=W; p[N].y=H; work(); swap(W,H);
for(LL i=1;i<=N;i++){
swap(p[i].x,p[i].y);
} work(); printf("%lld\n",ans*2);
return 0;
}

[Arc063F] Snuke's Coloring 2的更多相关文章

  1. [arc063F]Snuke's Coloring 2-[线段树+观察]

    Description 传送门 Solution 我们先不考虑周长,只考虑长和宽. 依题意得答案下限为max(w+1,h+1),并且最后所得一定是个矩形(矩形内部无点). 好的,所以!!!答案一定会经 ...

  2. ARC063F すぬけ君の塗り絵 2 / Snuke's Coloring 2

    题面 一句话题面:给你一些点,求这些点之中夹的最大的矩形周长.(考虑边界) Solution 首先是一个结论,答案矩形一定经过\(x=\frac{w}{2}\)或经过\(y=\frac{h}{2}\) ...

  3. 【ARC 063F】Snuke's Coloring 2

    Description There is a rectangle in the xy-plane, with its lower left corner at (0,0) and its upper ...

  4. すぬけ君の塗り絵 / Snuke's Coloring AtCoder - 2068 (思维,排序,贡献)

    Problem Statement We have a grid with H rows and W columns. At first, all cells were painted white. ...

  5. Snuke's Coloring 2-1

    There is a rectangle in the xy-plane, with its lower left corner at (0,0) and its upper right corner ...

  6. AtCoder Regular Contest 063 F : Snuke’s Coloring 2 (线段树 + 单调栈)

    题意 小 \(\mathrm{C}\) 很喜欢二维染色问题,这天他拿来了一个 \(w × h\) 的二维平面 , 初始时均为白色 . 然后他在上面设置了 \(n\) 个关键点 \((X_i , Y_i ...

  7. 2018.09.22 atcoder Snuke's Coloring 2(线段树+单调栈)

    传送门 就是给出一个矩形,上面有一些点,让你找出一个周长最大的矩形,满足没有一个点在矩形中. 这个题很有意思. 考虑到答案一定会穿过中线. 于是我们可以把点分到中线两边. 先想想暴力如何解决. 显然就 ...

  8. 2018.09.19 atcoder Snuke's Coloring(思维题)

    传送门 谁能想到这道题会写这么久. 本来是一道很sb的题啊. 就是每次选一个点只会影响到周围的九个方格,随便1e9进制就可以hash了,但是我非要作死用stl写. 结果由于技术不够高超,一直调不出来. ...

  9. [atARC063F]Snuke's Coloring 2

    首先,可以通过将所有$x_{i}=0$都选择第1类,其余选第2类,构造出一个以$(0,0)$和$(1,h)$为左下角和右上角的矩形,答案即为$2h+2$,类似地还可以构造出$2w+2$ 若最终的矩形不 ...

随机推荐

  1. oracle建表,设置主键,修改属性等

    --建表 create table book( book_id number(10), book_name varchar2(20), book_price number(10,2), book_au ...

  2. flask基础之AppContext应用上下文和RequestContext请求上下文(六)

    前言 应用上下文和请求上下文存在的目的,官方文档讲的很清楚,可参考: http://www.pythondoc.com/flask/appcontext.html 应用上下文对象在没有请求的时候是可以 ...

  3. 一个不错的linux学习资料下载的网址

    本文比较完整的讲述GNU make工具,涵盖GNU make的用法.语法.同时重点讨论如何为一个工程编写Makefile.作为一个Linux程序员,make工具的使用以及编写Makefile是必需的. ...

  4. 对于Linux平台下C语言开发中__sync_函数的认识(转)

    reference:http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html#Atomic-Builtins A built-i ...

  5. C#中HttpWebRequest的GetRequestStream执行的效率太低,甚至偶尔死掉

    为了提高httpwebrequest的执行效率,查到了一些如下设置 request.ServicePoint.Expect100Continue = false; request.ServicePoi ...

  6. 04 Effective Go 高效的go语言 重点内容

    Effective Go  高效的go语言 Introduction 介绍 Examples 例子 Formatting 格式 Commentary 评论 Names 名字 Package names ...

  7. Oracle 函数 “数据控制,指定某些人只能查看他权限范围内的信息”

    create or replace function work_plan_mask (p_schema VARCHAR2,p_table VARCHAR2) return Varchar2 AS -- ...

  8. 洛谷P2680运输计划

    传送门啦 要求的就是,把树上的一条边的权值设为0之后,所有路径中的最大值的最小值. 首先二分最大值,假设某次二分的最大值为x,我们首先找出所有大于x的路径(也就是我们需要通过改权缩短的路径),并把路径 ...

  9. python_docx制作word文档

    一.docx模块 Python可以利用python-docx模块处理word文档,处理方式是面向对象的.也就是说python-docx模块会把word文档,文档中的段落.文本.字体等都看做对象,对对象 ...

  10. python中round(四舍五入)的坑

    python中的round函数不能直接拿来四舍五入,一种替代方式是使用Decimal.quantize()函数. 具体内容待补. >>> round(2.675, 2) 2.67 可 ...