[NOI2005]维护数列 做题心得

[NOI2005]维护数列 做题心得

这题我很久以前就写了,但是经常90

现在仔细分析了一下我发现,原来是我写题的时候基础定义不明确。实际上,在信息竞赛中,我们通常只注重思想差不多对了就开始写代码,实际上,我们维护的东西具体定义:维护的是什么信息?具体怎么定义?可不可以是0?可不可以空?这些都要好好考虑,从理论上分析,确保没有漏洞了,再开始写代码。

还有就是,一定要小心细节啊啊啊

题解部分

分析题目

有6个操作,一个一个看

在...后插入(insback)

我们可以先把后面的数列建一颗splay树,找到它的树根对应点 (u) ,找地方插入。

那这样就是两个参数:插入的位置 (p),点 (u)

特判一下首尾插入,然后找到插入的位置,一前一后splay一下,然后就可以插入过来了。

具体的说,就是 (splay(kth(p))),然后 (splay(kth(p+1))),到 (kth(p)) 之下(p+1在p右边,显然是右儿子)

然后这时候,根的右儿子的左儿子就空出来一个位置,把 (u) 放在这里即可;同时,这里正好也是 (p)(p+1) 之间,满足我们"在...后插入"的需求

区间操作:区间删除,区间修改(翻转,覆盖)

首先我们搞一个提取区间的操作:通过区间两端(l-1,r+1)splay两下,把区间的点都打在一颗连续的子树里。

假设这颗子树的根是 (u)。并且称这个操作为 区间提取操作 (split)。接下来就好办了:

  • 对于删除,找到 (u) 之后断点它和父亲的边,并回收节点即可
  • 对于修改,找到 (u) 之后打对应的 tag 即可

这里有一个小细节:你可以选择回收或者不回收,不回收节约一点常数时间,但是浪费一点常数空间,并且多常数倍代码

我个人是不喜欢开太多空间,所以选择了回收

区间求和,与区间求最大连续子段和(非空)

前面一个很trival,细节部分主要在后面

众所周知最大连续子段和就是搞出来一个左连续最大,右连续最大,区间最大子段和,区间和,然后瞎上传一下就行了。

splay区间和线段树区间不太一样,splay 区间带一个中间点。所以我们要不同的考虑:

  1. 最大子段和落在左儿子/右儿子的内部,直接两边取max即可

    这也就说明左右儿子维护的最大子段和,应该是非空的

  2. 跨过中间 ,那就是当前的值+左儿子的右连续+右儿子的左连续

    由于我们已经保证了跨过中间点,所以左右儿子的连续都应该维护的是 可空

细节

0号节点的最大子段和应该是 (-infin)

要不然对于一段全负的区间,如果它左儿子/右儿子中有一个是空的,那么它就会把 0 号节点的最大子段和上传上来,认为当前最大子段和是 0 —— 而它应该是一个负的值。

还有就是,各种操作都特判一下首尾,别忘了update和pushdown

代码

#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
    #define N 1000006
    #define F(i,l,r) for(int i=l;i<=r;++i)
    #define D(i,r,l) for(int i=r;i>=l;--i)
    #define Fs(i,l,r,c) for(int i=l;i<=r;c)
    #define Ds(i,r,l,c) for(int i=r;i>=l;c)
    #define MEM(x,a) memset(x,a,sizeof(x))
    #define FK(x) MEM(x,0)
    #define Tra(i,u) for(int i=G.st(u),v=G.to(i);~i;i=G.nx(i),v=G.to(i))
    #define p_b push_back
    #define sz(a) ((int)a.size())
    #define all(a) a.begin(),a.end()
    #define iter(a,p) (a.begin()+p)
    #define PUT(a,n) F(i,1,n) printf("%d ",a[i]); puts("");
    int I() {char c=getchar(); int x=0; int f=1; while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar(); while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return ((f==1)?x:-x);}
    template <typename T> void Rd(T& arg){arg=I();}
    template <typename T,typename...Types> void Rd(T& arg,Types&...args){arg=I(); Rd(args...);}
    void RA(int *p,int n) {F(i,1,n) *p=I(),++p;}
    int n,m;
    void Input()
    {
        Rd(n,m);
    }
    struct info
    {
        int s,ls,rs,mx;
        info(int x=0,int len=1)
        {
            s=len*x;
            if (x>0) ls=rs=mx=s;
            else ls=rs=0,mx=x;
        }
    };
    info merge3(info a,int val,info b)
    {
        info res;
        res.s=a.s+val+b.s;
        res.ls=max(a.ls,a.s+val+b.ls);
        res.rs=max(b.rs,b.s+val+a.rs);
        res.mx=max({a.mx,b.mx,a.rs+b.ls+val});
        return res;
    }
    class SplayTree
    {
    public:
        int ch[N][2],fa[N];
        int val[N]; info s[N]; int sz[N];
        int cov[N],rev[N];
        int pool[N],psz=0;
        int tot=0,rt=0;
        #define ls(u) ch[u][0]
        #define rs(u) ch[u][1]
        bool id(int u) {return u==rs(fa[u]);}
        int  lk(int f,bool i,int u) {return fa[ch[f][i]=u]=f;}
        void cl(int u)
        {
            if (u==0) return;
            ls(u)=rs(u)=fa[u]=val[u]=sz[u]=0; s[u]=info(0);
            rev[u]=0; cov[u]=-114514;
        }
        int newp(int x=0)
        {
            int u=psz?pool[psz--]:++tot;
            cl(u); val[u]=x; s[u]=info(x);
            return u;
        }
        void cycall(int u)
        {
            if (ls(u)) cycall(ls(u));
            if (rs(u)) cycall(rs(u));
            cl(u); pool[++psz]=u;
        }
        void up(int u)
        {
            if (u==0) return;
            s[u]=merge3(s[ls(u)],val[u],s[rs(u)]);
            sz[u]=sz[ls(u)]+sz[rs(u)]+1;
        }
        void covone(int u,int c)
        {
            val[u]=cov[u]=c;
            s[u]=info(c,sz[u]);
        }
        void revone(int u)
        {
            swap(ls(u),rs(u)); swap(s[u].ls,s[u].rs);
            rev[u]^=1;
        }
        void down(int u)
        {
            if (cov[u]!=-114514)
            {
                rev[u]=0;
                if (ls(u)) covone(ls(u),cov[u]);
                if (rs(u)) covone(rs(u),cov[u]);
                cov[u]=-114514;
            }
            if (rev[u])
            {
                if (ls(u)) revone(ls(u));
                if (rs(u)) revone(rs(u));
                rev[u]=0;
            }
        }
        void downall(int u)
        {
            if (fa[u]) downall(fa[u]);
            down(u);
        }
        void rot(int u)
        {
            int f=fa[u],f2=fa[f],i=id(u),i2=id(f),w=ch[u][i^1];
            lk(f2,i2,lk(u,i^1,lk(f,i,w))); fa[0]=ch[0][i2]=0;
            up(f); up(u);
        }
        void sp(int u,int to=0)
        {
            downall(u);
            while(fa[u]!=to)
            {
                int f=fa[u];
                if (fa[f]!=to)
                {
                    rot(id(u)==id(f)?f:u);
                }
                rot(u);
            }
            if (!to) rt=u;
        }
        int kth(int k)
        {
            int u=rt;
            while(1)
            {
                down(u);
                if (k<=sz[ls(u)])
                {
                    u=ls(u);
                }
                else
                {
                    k-=sz[ls(u)];
                    if (k==1)
                    {
                        sp(u); return u;
                    }
                    else
                    {
                        k--; u=rs(u);
                    }
                }
            }
        }
        int build(int *p,int l,int r)
        {
            if (l>r) return 0;
            int mid=(l+r)>>1;
            int u=newp(p[mid]);
            lk(u,0,build(p,l,mid-1)); fa[0]=0;
            lk(u,1,build(p,mid+1,r)); fa[0]=0;
            up(u); return u;
        }
        void insback(int p,int uu)
        {
            if (p==0)
            {
                int u=rt; down(u);
                while(ls(u))
                {
                    u=ls(u); 
                    down(u);
                }
                sp(u); up(lk(u,0,uu)); 
            }
            else if (p==sz[rt])
            {
                int u=rt; down(u);
                while(rs(u))
                {
                    u=rs(u);
                    down(u);
                }
                sp(u); up(lk(u,1,uu));
            }
            else
            {
                int kl=kth(p),kr=kth(p+1);
                sp(kl); sp(kr,kl);
                up(lk(rs(rt),0,uu)); up(rt);
            }
        }
        int split(int l,int r)
        {
            if (l==1 and r==sz[rt]) return rt;
            if (l==1)
            {
                sp(kth(r+1)); return ls(rt);
            }
            if (r==sz[rt])
            {
                sp(kth(l-1)); return rs(rt);
            }
            int kl=kth(l-1),kr=kth(r+1);
            sp(kl); sp(kr,kl); return ls(rs(rt));
        }
        void rangedel(int l,int r)
        {
            int u=split(l,r),f=fa[u],i=id(u);
            ch[f][i]=0; cycall(u); 
            up(f); up(fa[f]);
        }
        void rangerev(int l,int r)
        {
            int u=split(l,r),f=fa[u],i=id(u);
            revone(u);
            up(f); up(fa[f]);
        }
        void rangecov(int l,int r,int c)
        {
            int u=split(l,r),f=fa[u],i=id(u);
            covone(u,c);
            up(f); up(fa[f]);
        }
        info query(int l,int r)
        {
            int u=split(l,r),f=fa[u],i=id(u);
            return s[u];
        }
    }T;
    int tmp[N];
    void Sakuya()
    {
        T.s[0].mx=-1e9;
        F(i,1,n) tmp[i]=I();
        T.rt=T.build(tmp,1,n);
        F(i,1,m)
        {
            char o[10]; scanf("%s",o);
            if (o[0]=='I')
            {
                int p,len; Rd(p,len);
                if (len==0) continue;
                F(j,1,len) tmp[j]=I();
                int u=T.build(tmp,1,len);
                T.insback(p,u);
            }
            if (o[0]=='D')
            {
                int p,len; Rd(p,len);
                if (len==0) continue;
                T.rangedel(p,p+len-1);
            }
            if (o[0]=='M' and o[2]=='K')
            {
                int p,len,c; Rd(p,len,c);
                if (len==0) continue;
                T.rangecov(p,p+len-1,c);                
            }
            if (o[0]=='R')
            {
                int p,len; Rd(p,len);
                if (len==0) continue;
                T.rangerev(p,p+len-1);
            }
            if (o[0]=='G')
            {
                int p,len; Rd(p,len);
                info tmp=T.query(p,p+len-1);
                printf("%d
",tmp.s);
            }
            if (o[0]=='M' and o[2]=='X')
            {
                info tmp=T.s[T.rt];
                printf("%d
",tmp.mx);
            }
        }
    }
    void IsMyWife()
    {
        Input();
        Sakuya();
    }
}
#undef int //long long
int main()
{
    Flandre_Scarlet::IsMyWife();
    getchar();
    return 0;
}
原文地址:https://www.cnblogs.com/LightningUZ/p/14619581.html