题解 P2042 【[NOI2005]维护数列】

· · 题解

本蒟蒻写的第一道平衡树大题,发个题解纪念一下。

前言:

本蒟蒻使用的是fhq_treap,相对来说可能会短一点(但是由于我太菜了所以看起来还是很长
本篇题解实现参考了 @x义x 大佬的代码(窝太菜了自己写不出

正题:

看题:惊人的时间限制——1s,于是可以先做一手卡常的准备了。再看空间上的限制和本题目中那一堆操作,想都不用想就知道肯定要维护一大堆东西,4e6的数据范围128MB开得下我觉得比较难,题目又保证了同一时间内节点数小于等于5e5,所以节点回收是肯定的。然后我们开始一步步解决这个题目。 先把节点定义放出来:

struct Node
{
    int lson,rson,siz,val,cov,rnd;   //cov为区间覆盖操作所要使用的值
    int lazy_rev,lazy_cov;  //这两个标记很显然吧emmm...
    int sum,pre_mx,suc_mx,all_mx;  //前缀最大值,后缀最大值,总最大值,和
}t[MAXN];int rt;

#define ls(x) t[x].lson //宏定义——偷懒专用
#define rs(x) t[x].rson

一、如何回收节点?

考虑开一个栈来存没有用的节点,删除节点的时候就把那些被删的节点堆进去就行,在代码里有清楚的体现

二、如何维护答案?

对于最大子段和的维护考虑维护一个前缀最大和,后缀最大和 和 自身这棵树内的最大和,如何合并呢?

inline void Update(int x)
{
    if(!x) return ;
    t[x].siz=t[ls(x)].siz+t[rs(x)].siz+1;
    t[x].sum=t[ls(x)].sum+t[rs(x)].sum+t[x].val;
    t[x].pre_mx=max(t[ls(x)].pre_mx,t[ls(x)].sum+t[x].val+t[rs(x)].pre_mx,0);
    t[x].suc_mx=max(t[rs(x)].suc_mx,t[rs(x)].sum+t[x].val+t[ls(x)].suc_mx,0);
    t[x].all_mx=max(t[x].val,t[x].val+t[ls(x)].suc_mx+t[rs(x)].pre_mx);
    if(ls(x)) t[x].all_mx=max(t[x].all_mx,t[ls(x)].all_mx);
    if(rs(x)) t[x].all_mx=max(t[x].all_mx,t[rs(x)].all_mx);
}

就这个样子。因为前缀后缀都是可以不取的所以可以为0,但是自身不能取0,因为题目强制必须取一个(有毒.....)

三、如何下放标记?

是不是fhq_treap的题目都只要在split的时候丢标记啊......
(反正它过了

四、这份代码有锅吗,可以抄吗

显然你是可以抄的
但是这个代码有一个很神奇事情就是开不了O2,一开O2就RE,有没有哪位大佬告诉我这是为啥呀5555.
Orz Orz Orz

五、关于代码里的max

我比较懒,就重载了一个三个参数的max

六、code

#include <cstdio>

#define R register
const int MAXN=5e5+10;
const int RAND_1=1e9+7;
const int RAND_2=1e9+9;

inline int read()
{
    char a=getchar();int x=0,f=1;
    for(;a>'9'||a<'0';a=getchar()) if(a=='-') f=-1;
    for(;a>='0'&&a<='9';a=getchar()) x=x*10+a-'0';
    return x*f;
}

int Seed='L'+'C'+'N'+'B'+171098569;
inline int swap(int &x,int &y) { x^=y;y^=x;x^=y; }
inline int max(int x,int y) { return x>y?x:y;}
inline int max(int x,int y,int z) { return max(x,max(y,z)); }
inline int rand() { return Seed=(Seed*RAND_1+0x7f7f7f7f)*RAND_2*Seed; }

int n,m;
int stk[MAXN],cnt;

struct Node
{
    int lson,rson,siz,val,cov,rnd;
    int lazy_rev,lazy_cov;
    int sum,pre_mx,suc_mx,all_mx;
}t[MAXN];int rt;

#define ls(x) t[x].lson
#define rs(x) t[x].rson

inline int New(int k)
{
    int x=stk[cnt--];
    ls(x)=rs(x)=t[x].cov=t[x].lazy_rev=t[x].lazy_cov=0;
    t[x].siz=1;
    t[x].val=t[x].sum=k;
    t[x].pre_mx=t[x].suc_mx=max(0,k);
    t[x].all_mx=k;
    t[x].rnd=rand();
    return x;
}

inline void Update(int x)
{
    if(!x) return ;
    t[x].siz=t[ls(x)].siz+t[rs(x)].siz+1;
    t[x].sum=t[ls(x)].sum+t[rs(x)].sum+t[x].val;
    t[x].pre_mx=max(t[ls(x)].pre_mx,t[ls(x)].sum+t[x].val+t[rs(x)].pre_mx,0);
    t[x].suc_mx=max(t[rs(x)].suc_mx,t[rs(x)].sum+t[x].val+t[ls(x)].suc_mx,0);
    t[x].all_mx=max(t[x].val,t[x].val+t[ls(x)].suc_mx+t[rs(x)].pre_mx);
    if(ls(x)) t[x].all_mx=max(t[x].all_mx,t[ls(x)].all_mx);
    if(rs(x)) t[x].all_mx=max(t[x].all_mx,t[rs(x)].all_mx);
}

inline void Reverse(int x)
{
    if(!x) return ;
    swap(ls(x),rs(x));
    swap(t[x].pre_mx,t[x].suc_mx);
    t[x].lazy_rev^=1;
}

inline void Cover(int x,int col)
{
    t[x].val=t[x].cov=col;
    t[x].sum=t[x].siz*col;
    t[x].pre_mx=t[x].suc_mx=max(0,t[x].sum);
    t[x].all_mx=max(col,t[x].sum);
    t[x].lazy_cov=1;
}

inline void Pushdown(int x)
{
    if(!x) return ;
    if(t[x].lazy_rev)
    {
        if(ls(x)) Reverse(ls(x));
        if(rs(x)) Reverse(rs(x));
        t[x].lazy_rev=0;
    }
    if(t[x].lazy_cov)
    {
        if(ls(x)) Cover(ls(x),t[x].cov);
        if(rs(x)) Cover(rs(x),t[x].cov);
        t[x].lazy_cov=t[x].cov=0;
    }
}

inline void Delete(int x)
{
    if(!x) return;
    stk[++cnt]=x;
    if(ls(x)) Delete(ls(x));
    if(rs(x)) Delete(rs(x));
}

inline void Split(int now,int k,int &x,int &y)
{
    if(!now) { x = y = 0; return ; }
    Pushdown(now);
    if(t[ls(now)].siz+1<=k)
    {
        x=now;
        Split(rs(now),k-t[ls(now)].siz-1,rs(now),y);
    } 
    else
    {
        y=now;
        Split(ls(now),k,x,ls(now));
    }
    Update(now);
}

inline int Merge(int x,int y)
{
    if(!x||!y) return x|y;
    if(t[x].rnd<t[y].rnd)
    {
        Pushdown(x);
        rs(x)=Merge(rs(x),y);
        Update(x); return x;
    }
    else
    {
        Pushdown(y);
        ls(y)=Merge(x,ls(y));
        Update(y); return y;
    }
}

int array[MAXN];

inline int Build(int l,int r)
{
    if(l==r) return New(array[l]);
    int mid=l+r;mid>>=1;
    return Merge(Build(l,mid),Build(mid+1,r));
}

char opt[10];

int main()
{
    n=read();m=read();
    for(R int i=1;i<MAXN;i++) stk[++cnt]=i;
    for(R int i=1;i<=n;i++) array[i]=read();
    rt=Build(1,n);
    while(m--)
    {
        scanf("%s",opt);
        if(opt[0]=='I')
        {
            int pos=read(),tot=read();
            int x,y;
            Split(rt,pos,x,y);
            for(R int i=1;i<=tot;i++) array[i]=read();
            x=Merge(x,Build(1,tot));
            rt=Merge(x,y);
        }
        if(opt[0]=='D')
        {
            int pos=read(),tot=read();
            int x,y,z;
            Split(rt,pos-1,x,y);
            Split(y,tot,y,z);
            Delete(y);
            rt=Merge(x,z);
        }
        if(opt[2]=='K')
        {
            int pos=read(),tot=read(),col=read();
            int x,y,z;
            Split(rt,pos-1,x,y);
            Split(y,tot,y,z);
            Cover(y,col);
            rt=Merge(Merge(x,y),z);
        }
        if(opt[0]=='R')
        {
            int pos=read(),tot=read();
            int x,y,z;
            Split(rt,pos-1,x,y);
            Split(y,tot,y,z);
            Reverse(y);
            rt=Merge(Merge(x,y),z);
        }
        if(opt[0]=='G')
        {
            int pos=read(),tot=read();
            int x,y,z;
            Split(rt,pos-1,x,y);
            Split(y,tot,y,z);
            printf("%d\n",t[y].sum);
            rt=Merge(Merge(x,y),z);
        }
        if(opt[2]=='X')
        {
            printf("%d\n",t[rt].all_mx);
        }
    }
    return 0;
}