[NOI2005]维护数列——平衡树观止

本题题解并不详细,不推荐大家看这一篇。

题目描述

请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格)

100%的数据中,任何时刻数列中最多含有 500 000 个数。

100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。

100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 。

题解:

刷完普通平衡树,文艺平衡树板子后,本题纯靠自己想,用了3h打码,4h调试,共7h多终于AC了。

此题我认为堪称“平衡树观止”

题目就是这么地裸。但就是让你写不出来。

粗略地说一下splay题解:

要用到:

1.n+2个点,1,n+2是方便提取用的。

2.哨兵0号点,

3.每个点维护:fa,ch[2],sz,sum,val,lm,rm,ans最后三个是最大子段和用的。

和标记:chan,rev

4.用long long

知识点:

1.区间提取,l-1到根,r+1到根的右儿子。根右儿子的左子树就是操作区间。

2.区间打标记,直接打。

3.找区间左端点,右端点等,返回第k大位置节点编号。

显然不能直接把端点当做编号。因为根本不知道原始编号转到哪里去了。

4.pushdown时机:

pushdown本质是为了将序列保持真正的情况,所以一旦触及,必须pushdown,否则形态一变,子树一换,都完了。

每次查找kth的x,因为每次查找对应一次splay,必须一路上都pushdown,

并且影响的只有rt到x路径上的点,所以其他位置可以不用pushdown

子树内部也是不会动的,不用pushdown。

5.pushup时机:

本质是为了更新信息,所以一个节点变化了,或者其子树变化了,都要pushup

splay里面有,也是路径上改变的点都会pushup的。

另外,操作区间操作后,该子树可能有了变化,还要pushup(根右儿子),pushup(根),别的节点也不会被这次操作影响。

6.1号点和n+2号点。为了不影响答案(可能是负数),所以权值为-inf,并且这两个点一定要保证在区间的两端。

7.0号哨兵

因为我这里是钦定lm,rm,ans都必须选择一个。所以0号的rm,lm,ans都是-inf,才不会因为设成0而取不到负数答案。

8.卡空间(bzoj64MB)

而同一时刻最多500000个。必须垃圾回收,dp[N],dc

操作:

1.插入:直接插成一个链可以,但是之后复杂度并不优秀。

可以分治处理。每次插入mid递归l,mid-1和mid+1,r,数的高度就直接logn了。

开始的加入原数列也是。

对于新加入一些数,先像这样建成一棵树,然后类似区间提取pos,pos+1。

那么,pos+1左儿子就是新树根的fa了,直接嫁接上去。记得pushup(pos+1)与(pos)

见ins,pre函数

2.删除。区间提取、然后直接删除rt的右儿子的左儿子。

要先进入这个子树,放进回收池里。

3.修改。区间提取,直接改。

4.翻转。区间提取。翻转标记。

注意,必须打标记的同时,就要翻转儿子,交换lm,rm

因为虽然是懒标记,但是对于这个节点的影响必须处理。

否则splay时可能会出锅。

因为x左右儿子会有标记,但不翻转,然后rotate(x)会交换子树,pushup(y)就把没有真正正确的x曾经的子树信息记录上去了。

5.区间和。区间提取。直接返回sum

6.最大子段和。直接返回t[rt].ans

注意事项:

1.保护哨兵,保护哨兵,保护哨兵。

2.任何时候,在splay(x)之前,必须确定x路径上的所有点都pushdown了。

3.pushup中,t[x].ans情况较多,不要忘了可以是t[x].val

4.swap(lm,rm)别错了。

代码:

#include<bits/stdc++.h>
#define rs t[x].ch[1]
#define ls t[x].ch[0]
#define numb ch-'0'
#define ri register int
#define il inline
using namespace std;
typedef long long ll;
const int N=500000+5;
const ll inf=(1LL*1<<61);
char ch;
il void rdint(int &x){
    x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
il void rdll(ll &x){
    x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
struct node{
    int ch[2],fa;
    ll rm,lm,sum,ans;
    int rev;
    ll chan;
    ll val;
    int sz;
    void init(int f,ll v){
        fa=f,val=v;rm=v;lm=v,ans=v,sum=v;
        rev=0,chan=inf;
        sz=1;
    }
}t[N];
il ll Max(ll a,ll b){
    return a>b?a:b;
}
int dc,dp[N],pc;
int n,m,rt;
ll st[N];
il int nc(){
    int r=dc?dp[dc--]:++pc;
    memset(t+r,0,sizeof (node));return r;
}
il void pushup(int x){
    t[x].sum=t[t[x].ch[0]].sum+t[t[x].ch[1]].sum+t[x].val;
    t[x].rm=Max(t[t[x].ch[1]].rm,Max(t[t[x].ch[1]].sum+t[x].val,t[t[x].ch[1]].sum+t[x].val+t[t[x].ch[0]].rm));
    t[x].lm=Max(t[t[x].ch[0]].lm,Max(t[t[x].ch[0]].sum+t[x].val,t[t[x].ch[0]].sum+t[x].val+t[t[x].ch[1]].lm));
    t[x].ans=Max(t[x].lm,t[x].rm);
    t[x].ans=Max(t[x].ans,Max(t[t[x].ch[0]].rm+t[x].val+t[t[x].ch[1]].lm,Max(t[t[x].ch[0]].rm+t[x].val,t[x].val+t[t[x].ch[1]].lm)));
    t[x].ans=Max(t[x].ans,Max(t[t[x].ch[0]].ans,t[t[x].ch[1]].ans));
    t[x].ans=Max(t[x].ans,t[x].val);//bug 2
    t[x].sz=t[t[x].ch[0]].sz+t[t[x].ch[1]].sz+1;
}
il void pushdown(int x){
    if(t[x].chan!=inf){
        if(ls){
        t[ls].chan=t[x].chan;
        t[ls].val=t[x].chan;
        t[ls].sum=t[ls].val*t[ls].sz;
        t[ls].rm=t[ls].lm=t[ls].ans=t[ls].val>0?t[ls].sum:t[ls].val;
        }
        if(rs){
        t[rs].chan=t[x].chan;
        t[rs].val=t[x].chan;
        t[rs].sum=t[rs].val*t[rs].sz;
        t[rs].rm=t[rs].lm=t[rs].ans=t[rs].val>0?t[rs].sum:t[rs].val;
        }
        t[x].chan=inf;
    }
    if(t[x].rev){
        if(ls&&t[ls].val!=-inf){
        t[ls].rev^=1;
        swap(t[ls].lm,t[ls].rm);//bug1
        }
        if(rs&&t[rs].val!=-inf){
        t[rs].rev^=1;
        swap(t[rs].lm,t[rs].rm);//bug1
        }
        swap(ls,rs);
        t[x].rev=0;
    }
}
il void rotate(int x){
    int y=t[x].fa,d=t[y].ch[1]==x;
    t[t[y].ch[d]=t[x].ch[!d]].fa=y;
    t[t[x].fa=t[y].fa].ch[t[t[y].fa].ch[1]==y]=x;
    t[t[x].ch[!d]=y].fa=x;
    pushup(y);
}
il void splay1(int x,int f){
    while(t[x].fa!=f){
        int y=t[x].fa,z=t[y].fa;
        if(z!=f){
            rotate((t[y].ch[0]==x)==(t[z].ch[0]==y)?y:x);
        }
        rotate(x);
    }
    pushup(x);
    if(f==0) rt=x;
}
il int kth(int k){
    int x=rt;
    while(1){
        pushdown(x);
        int d=k-t[t[x].ch[0]].sz;
        if(d<=0) x=t[x].ch[0];
        else if(d==1) return x;
        else{
            k=d-1;
            x=t[x].ch[1];
        }
    }
}
int newrt;
il void splay2(int x,int f){
    while(t[x].fa!=f){
        int y=t[x].fa,z=t[y].fa;
        if(z!=f){
            rotate((t[y].ch[0]==x)==(t[z].ch[0]==y)?y:x);
        }
        rotate(x);
    }
    pushup(x);
    if(f==0) newrt=x;
}
il void build(ll v){
    if(!newrt){
        newrt=nc();
        t[newrt].init(0,v);
        return;
    }
    int x=newrt;
    while(1){
        if(!t[x].ch[1]){
            t[x].ch[1]=nc();
            t[t[x].ch[1]].init(x,v);
            x=t[x].ch[1];
            break;
        }
        x=t[x].ch[1];
    }
    splay2(x,0);
}
il int pre(int l,int r,int f){
    if(l>r){
        return 0;
    }
    int mid=(l+r)>>1;
    int x=nc();
    t[x].init(f,st[mid]);
    t[x].ch[0]=pre(l,mid-1,x);
    t[x].ch[1]=pre(mid+1,r,x);
    pushup(x);
    return x;
}
il void ins(int pos,int tot){
    newrt=0;
    for(ri i=1;i<=tot;i++){
        rdll(st[i]);
    }
    newrt=pre(1,tot,0);
    int x=kth(pos+1);
    int y=kth(pos+2);
    splay1(x,0);
    splay1(y,x);
    t[y].ch[0]=newrt;
    t[newrt].fa=y;
    pushup(y);
    pushup(x);
}
il void del(int x){
    if(t[x].ch[0]) del(t[x].ch[0]);
    dp[++dc]=x;
    if(t[x].ch[1]) del(t[x].ch[1]);
}
il void remove(int pos,int tot){
    int l=kth(pos);
    int r=kth(pos+tot+1);
    splay1(l,0);
    splay1(r,l);
    del(t[r].ch[0]);
    t[r].ch[0]=0;
    pushup(r);
    pushup(l);
}
il void upda(int pos,int tot,ll c){
    int l=kth(pos);
    int r=kth(pos+tot+1);
    splay1(l,0);
    splay1(r,l);
    
    int x=t[r].ch[0];
    t[x].chan=c;
    t[x].val=c;
    t[x].sum=t[x].val*t[x].sz;
    t[x].rm=t[x].lm=t[x].ans=t[x].val>0?t[x].sum:t[x].val;
    
    pushup(r);
    pushup(l);
}
il void reverse(int pos,int tot){
    int l=kth(pos);
    int r=kth(pos+tot+1);
    splay1(l,0);
    splay1(r,l);
    
    int x=t[r].ch[0];
    t[x].rev^=1;
    swap(t[x].lm,t[x].rm);    
    
    pushup(r);
    pushup(l);
}
il ll qs(int pos,int tot){
    int l=kth(pos);
    int r=kth(pos+tot+1);
    splay1(l,0);
    splay1(r,l);
    
    int x=t[r].ch[0];
    int ret=t[x].sum;
    pushdown(x);//bug 3
    splay1(x,0);
    return ret;
}

int main()
{
    t[0].lm=t[0].rm=t[0].ans=-inf;//warning warning warning !!! 
    t[0].sz=0;t[0].sum=0;
    scanf("%d%d",&n,&m);
    st[1]=-inf;
    for(int i=2;i<=n+1;i++){
        rdll(st[i]);
    }
    st[n+2]=-inf;
    
    rt=pre(1,n+2,0);
    char lp[20];
    int pos,tot;
    ll c;
    int cnt=0;
    for(ri i=1;i<=m;i++){
        ch=getchar();
        while(ch>'Z'||ch<'A')ch=getchar();
        for(cnt=0;(ch=='-')||(ch<='Z'&&ch>='A');ch=getchar())lp[++cnt]=ch;
        if(lp[1]=='I'){
            rdint(pos),rdint(tot);
            if(tot==0) continue;
            ins(pos,tot);
        }
        else if(lp[1]=='D'){
            rdint(pos),rdint(tot);
            if(tot==0) continue;
            remove(pos,tot);
        }
        else if(lp[1]=='M'&&lp[3]=='K'){
            rdint(pos),rdint(tot);rdll(c);
            if(tot==0) continue;
            upda(pos,tot,c);
        }
        else if(lp[1]=='M'&&lp[3]=='X'){
            printf("%lld\n",t[rt].ans);
        }
        else if(lp[1]=='G'){
            rdint(pos),rdint(tot);
            if(tot==0) printf("0\n");
            else printf("%lld\n",qs(pos,tot));
        }
        else if(lp[1]=='R'){
            rdint(pos),rdint(tot);
            if(tot==0) continue;
            reverse(pos,tot);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Miracevin/p/9643977.html
今日推荐