ARC 063 F

在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);
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/81381133
063