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

Description

传送门

Solution

我们先不考虑周长,只考虑长和宽。

依题意得答案下限为max(w+1,h+1),并且最后所得一定是个矩形(矩形内部无点)。

好的,所以!!!答案一定会经过$y=frac{h}{2}$或$x=frac{w}{2}$。否则答案就。。显然不满足下限了啊。

我们先考虑答案经过$y=frac{h}{2}$的情况。另一种情况同理(或者把图翻过来也可以)

我们维护两个单调栈和一个线段树。一个栈a维护直线下方的递减y序列和序列内点的编号,另一个栈b维护直线上方的递增y序列和序列内点的编号,线段树的叶子节点(代表点j)为由当前节点i到j+1所能取到的竖直方向最大值减去x[j](也可理解为矩阵的一条边在j处)。这样ans就为max(ans,x[i+1]+maxn[1])。这里的maxn[1]是指线段树根节点。线段树维护最大值。

单调栈和线段树的更新:对于新添进来的节点i,如果a[top].y<y[i],则线段树区间[a[top].id,i-1]这一段区间减去y[i]-a[top].y;对于b的更新同理。最后添加(id=i,y=0)到a栈,(id=i,y=h)到b栈,(h-x[i])到线段树代表区间为[i,i]的节点。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define x first
#define y second 
using namespace std;
int w,h,n;
struct P{int x,y;
friend bool operator<(P a,P b) {return a.x==b.x?a.y<b.y:a.x<b.x;}}p[300010];
 
int mx[1200010],tag[1200010];
int tp1,tp2,nxt;
pair<int,int> l[300010],r[300010];
void downtag(int k){mx[k<<1]+=tag[k];mx[k<<1|1]+=tag[k];
tag[k<<1]+=tag[k];tag[k<<1|1]+=tag[k];tag[k]=0;}
void modify(int k,int l,int r,int askx,int asky,int x)
{
    if (askx<=l&&r<=asky) {tag[k]+=x;mx[k]+=x;return;}
    int mid=(l+r)/2;
    if (tag[k]) downtag(k);
    if (askx<=mid) modify(k<<1,l,mid,askx,asky,x);
    if (asky>mid) modify(k<<1|1,mid+1,r,askx,asky,x);
    mx[k]=max(mx[k<<1],mx[k<<1|1]);
}
int ans=0;
void solve()
{
    memset(mx,0,sizeof(mx));
    memset(tag,0,sizeof(tag));
    sort(p+1,p+n+1);
    tp1=tp2=0;
    for (int i=1;i<=n;i++)
    {
        if (p[i].y<=h/2)
        {
            nxt=i-1;
            while (tp1&&p[i].y>l[tp1].y)
            {
                modify(1,1,n,l[tp1].x,nxt,l[tp1].y-p[i].y);
                nxt=l[tp1].x-1;tp1--;
            }
            if (nxt!=i-1) l[++tp1]=make_pair(nxt+1,p[i].y);
        }
        else
        {
            nxt=i-1;
            while (tp2&&p[i].y<r[tp2].y)
            {
                modify(1,1,n,r[tp2].x,nxt,p[i].y-r[tp2].y);
                nxt=r[tp2].x-1;tp2--;
            }
            if (nxt!=i-1) r[++tp2]=make_pair(nxt+1,p[i].y);
        }
        l[++tp1]=make_pair(i,0);
        r[++tp2]=make_pair(i,h);
        modify(1,1,n,i,i,h-p[i].x);
        ans=max(ans,p[i+1].x+mx[1]);
    }
}
int main()
{
    scanf("%d%d%d",&w,&h,&n);
    for (int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);
    p[++n]=P{0,0};p[++n]=P{w,h};
    solve();
    for (int i=1;i<=n;i++) swap(p[i].x,p[i].y);swap(w,h);
    solve();
    printf("%d",ans<<1);
}
原文地址:https://www.cnblogs.com/coco-night/p/9677691.html