在w * h 的方格中
求不含指定格点的边与方格平行的长方形的最大周长
考虑内部没有任何格点(不管是否指定)的长方形
发现周长最大为min(w , h) * 2 + 2
所以长方形一定穿过横着的中线和竖着的中线的其中一条。
考虑穿过一条线的长方形如何计算?
dp[i][j]代表以横坐标为i为右边界,横坐标j为左边界的最大周长,
会发现dp值和i,j,还有i与j之间纵坐标最靠近这条线的点的纵坐标有关,
那么在i增大的过程中,用线段树高效维护dp[i][j],i那一维可以省掉,再随时取最大值就行,
代码全是细节:
ACcode:
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define maxn 300005
#define lc now<<1
#define rc lc|1
using namespace std;
int w,h,n,x[maxn],y[maxn],num[maxn],up[maxn],dn[maxn],c[maxn],z[maxn];
inline bool cmp(const int &a,const int &b){ return x[a]<x[b]; }
int Max[maxn*10],lazy[maxn*10];
inline void dt(int now)
{ if(lazy[now]){ Max[now]+=lazy[now],lazy[lc]+=lazy[now],lazy[rc]+=lazy[now],lazy[now]=0; } }
inline void upd(int now){ Max[now]=max(Max[lc],Max[rc]); }
void Add(int now,int l,int r,int ql,int qr,int val)
{
dt(now);
if(qr<l || ql>r) return;
if(ql<=l && r<=qr){ lazy[now]+=val,dt(now);return; }
int mid=(l+r)>>1;
Add(lc,l,mid,ql,qr,val),Add(rc,mid+1,r,ql,qr,val);
upd(now);
}
int Query(int now,int l,int r,int ql,int qr)
{
dt(now);
if(qr<l || ql>r) return -0x3f3f3f3f;
if(ql<=l && r<=qr) return Max[now];
int mid=(l+r)>>1;
int tmp=max(Query(lc,l,mid,ql,qr) , Query(rc,mid+1,r,ql,qr));
upd(now);
return tmp;
}
int ans=0,Q[2][maxn],tp[2];
void solve()
{
tp[0]=tp[1]=0;
memset(Max,0,sizeof Max);
memset(lazy ,0 ,sizeof lazy);
sort(c+1,c+1+n,cmp);
num[0]=0;
for(int i=1;i<=n;i++) if(i==1 || x[c[i-1]] != x[c[i]]) num[++num[0]] = x[c[i]];
for(int i=1;i<=num[0];i++) up[i] = h , dn[i] = 0;
int loc = h/2;
for(int i=1;i<=n;i++)
{
x[c[i]] = lower_bound(num+1,num+1+num[0],x[c[i]]) - num;
if(y[c[i]] >= loc) up[x[c[i]]] = min(up[x[c[i]]] , y[c[i]]);
if(y[c[i]] <= loc) dn[x[c[i]]] = max(dn[x[c[i]]] , y[c[i]]);
}
for(int i=1;i<=num[0];i++)
{
ans=max(ans,Query(1,1,num[0],1,i-1) - (w - num[i]));
if(i) Add(1,1,num[0],i-1,i-1,max(up[i-1],up[i])-min(dn[i-1],dn[i])-h);
for(;tp[0] && up[Q[0][tp[0]-1]]>up[i];tp[0]--)
Add(1,1,num[0],Q[0][tp[0]-2],i-1,max(up[i],up[Q[0][tp[0]-2]]) - up[Q[0][tp[0]-1]]);
Q[0][tp[0]++] = i;
for(;tp[1] && dn[Q[1][tp[1]-1]]<dn[i];tp[1]--)
Add(1,1,num[0],Q[1][tp[1]-2],i-1,dn[Q[1][tp[1]-1]] - min(dn[i],dn[Q[1][tp[1]-2]]));
Q[1][tp[1]++] = i;
Add(1,1,num[0],i,i,h+w-num[i]);
}
}
int main()
{
scanf("%d%d%d",&w,&h,&n);
for(int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]),c[i]=i;
x[n+1] = 0 , y[n+1] = h/2 , c[n+1] = n+1;
x[n+2] = w , y[n+2] = h/2 , c[n+2] = n+2;
x[n+3] = w/2 , y[n+3] = 0 , c[n+3] = n+3;
x[n+4] = w/2 , y[n+4] = h , c[n+4] = n+4;
n+=4;
memcpy(z,x,sizeof x);
solve();
swap(w,h);
memcpy(x,z,sizeof z);
for(int i=1;i<=n;i++) swap(x[i],y[i]);
solve();
printf("%d\n",ans*2);
}