首先发现一定能找到一个最优解使得矩形的每条边要么是边界,要么有一个关键点,所以转化为求周长最大的内部不存在关键点的矩形。
不难发现选择一竖条或者一横条是一定合法的,那么答案下界就至少是
2(max(h,w)+1)
2
(
max
(
h
,
w
)
+
1
)
,那么最优解一定过
x=w2
x
=
w
2
或者
y=h2
y
=
h
2
,因为在某个四分之一矩形内部是不可能达到答案下界的。
先考虑经过
x=w2
x
=
w
2
的答案(另一部分同理),那么枚举上边界
yL
y
L
,用两个单调栈维护下边界
yR
y
R
递增时的左右边界
xL,xR
x
L
,
x
R
,可以
O(n2)
O
(
n
2
)
求解。其实对于
yR
y
R
递增的过程,我们可以用线段树维护
yL=1..n
y
L
=
1..
n
的最小周长,单调栈的操作相当于在线段树上区间加减,然后维护一个全局最小值即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define chkmin(a,b) a=min(a,b)
#define chkmax(a,b) a=max(a,b)
#define mid (l+r>>1)
#define N 200010
using namespace std;
int w,h,n,m,z[N],hl[N],hr[N],ans,topl,topr;
int read()
{
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*f;
}
struct pt
{
int x,y;
}a[N],sl[N],sr[N];
struct tree
{
int add,mx;
tree *ls,*rs;
tree(){ls=rs=0;mx=add=0;}
void update()
{
mx=max(ls->mx,rs->mx);
}
void cal(int d)
{
mx+=d;add+=d;
}
void pushdown()
{
ls->cal(add);rs->cal(add);
add=0;
}
void build(int l,int r)
{
if(l==r) return ;
(ls=new tree)->build(l,mid);
(rs=new tree)->build(mid+1,r);
}
void mdf(int l,int r,int lx,int rx,int d)
{
if(lx>rx||d==0) return ;
if(l==lx&&r==rx) {cal(d);return ;}
pushdown();
if(rx<=mid) ls->mdf(l,mid,lx,rx,d);
else if(lx>mid) rs->mdf(mid+1,r,lx,rx,d);
else ls->mdf(l,mid,lx,mid,d),rs->mdf(mid+1,r,mid+1,rx,d);
update();
}
}*xtr;
void work()
{
for(int i=1;i<=n;i++)
z[i]=a[i].y;
sort(z,z+n+1);z[n+1]=h;
m=unique(z,z+n+2)-z-1;
for(int i=1;i<=n;i++)
a[i].y=lower_bound(z,z+m+1,a[i].y)-z;
(xtr=new tree)->build(0,m);
for(int i=0;i<=m;i++)
hl[i]=0,hr[i]=w;
for(int i=1;i<=n;i++)
if(a[i].x<=(w>>1)) chkmax(hl[a[i].y],a[i].x);
else chkmin(hr[a[i].y],a[i].x);
topl=topr=0;
xtr->mdf(0,m,0,m,w);
for(int i=1;i<=m;i++)
{
xtr->mdf(0,m,0,i-1,z[i]-z[i-1]);
chkmax(ans,xtr->mx);
for(;topl&&hl[i]>=sl[topl].x;topl--)
xtr->mdf(0,m,sl[topl-1].y,sl[topl].y-1,sl[topl].x-hl[i]);
for(;topr&&hr[i]<=sr[topr].x;topr--)
xtr->mdf(0,m,sr[topr-1].y,sr[topr].y-1,hr[i]-sr[topr].x);
xtr->mdf(0,m,i-1,i-1,hr[i]-hl[i]-w);
sl[++topl]=(pt){hl[i],i};sr[++topr]=(pt){hr[i],i};
}
}
int main()
{
w=read();h=read();n=read();
for(int i=1;i<=n;i++)
a[i].x=read(),a[i].y=read();
work();
for(int i=1;i<=n;i++)
a[i].y=z[a[i].y];
swap(w,h);
for(int i=1;i<=n;i++)
swap(a[i].x,a[i].y);
work();
printf("%d",ans<<1);
return 0;
}