[BZOJ1500][NOI2005]维护数列(无旋Treap)

1500: [NOI2005]维修数列

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 16199   Solved: 5391

Description

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

[BZOJ1500][NOI2005]维护数列(无旋Treap)_第1张图片

Input

输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。

第2行包含N个数字,描述初始时的数列。

以下M行,每行一条命令,格式参见问题描述中的表格。

任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。

插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM

Sample Output

-1
10
1
10

思路&&分析

    这道题很显然也是一个平衡树题,我依旧是用无旋Treap做的,不过要注意这题内存限制只有64M,所以我们不能直接开400W个节点。又因为题目说过任何时刻数列中不会有超过50W个数,所以我们可以开50W个节点,然后进行节点回收。还需要注意的是Pushdown和修改的时候要注意一下小细节的部分,比如在Pushup时要判断他是否有两个孩子,否则就会默认把节点0认为孩子,这样是会挂的……(我就是因为这样在luogu上WA90了好几发)。

Code

#pragma GCC optimize(3)
#include
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int base=48271,maxn=500010;
int seed=233,cnt,rec[maxn],tp,stk[maxn],rtp,a[maxn],rt;
inline int Rand() {
    return seed=(int)(1ll*seed*base%INT_MAX);
}
inline void Recycle(int x) {
    rec[++rtp]=x;
}
struct Treap {
    int sz,ls,rs,val,sum,lmx,rmx,rev,cov,fix,mx;
    Treap(int _val=0):val(_val){ls=rs=sz=rev=0;sum=lmx=rmx=mx=val;cov=-2333;fix=Rand();}
}tr[maxn];
inline void Clear(int o) {
    if(!o)
        return;
    Clear(tr[o].ls);
    Clear(tr[o].rs);
    Recycle(o);
}
inline int Newnode(int val) {
    int tmp=rtp?rec[rtp--]:++cnt;
    tr[tmp]=Treap(val);
    tr[tmp].sz=1;
    return tmp;
}
inline void Cover(int o,int x) {
    tr[o].sum=x*tr[o].sz;
    tr[o].val=x;
    tr[o].lmx=tr[o].rmx=tr[o].mx=max(tr[o].sum,x);
    tr[o].cov=x;
}
inline void Revnode(int o) {
    swap(tr[o].ls,tr[o].rs);
    swap(tr[o].lmx,tr[o].rmx);
    tr[o].rev^=1;
}
inline int Sum(int o) {
    return !o?0:tr[o].sum;
}
inline int Sz(int o) {
    return !o?0:tr[o].sz;
}
inline int Lmx(int o) {
    return !o?-2333:tr[o].lmx;
}
inline int Rmx(int o) {
    return !o?-2333:tr[o].rmx;
}
inline int Mx(int o) {
    return !o?-2333:tr[o].mx;
}
inline void Pushup(int o) {
    if(!o)
        return;
    tr[o].sz=Sz(tr[o].ls)+1+Sz(tr[o].rs);
    tr[o].sum=Sum(tr[o].ls)+tr[o].val+Sum(tr[o].rs);
    tr[o].lmx=max(Lmx(tr[o].ls),Sum(tr[o].ls)+tr[o].val+max(Lmx(tr[o].rs),0));
    tr[o].rmx=max(Rmx(tr[o].rs),Sum(tr[o].rs)+tr[o].val+max(Rmx(tr[o].ls),0));
    tr[o].mx=max(max(0,Rmx(tr[o].ls))+tr[o].val+max(0,Lmx(tr[o].rs)),max(Mx(tr[o].ls),Mx(tr[o].rs)));
}
inline void Pushdown(int o) {
    if(!o)
        return;
    if(tr[o].rev) {
        if(tr[o].ls)
            Revnode(tr[o].ls);
        if(tr[o].rs)
            Revnode(tr[o].rs);
        tr[o].rev=0;
    }
    if(tr[o].cov!=-2333) {
        if(tr[o].ls)
            Cover(tr[o].ls,tr[o].cov);
        if(tr[o].rs)
            Cover(tr[o].rs,tr[o].cov);
        tr[o].cov=-2333;
    }
}
inline int Merge(int a,int b) {
    if(!a||!b)
        return a|b;
    Pushdown(a);
    Pushdown(b);
    if(tr[a].fixreturn a;
    }
    else {
        tr[b].ls=Merge(a,tr[b].ls);
        Pushup(b);
        return b;
    }
}
inline pair<int,int> Split(int o,int k) {
    if(!o)
        return make_pair(0,0);
    Pushdown(o);
    if(Sz(tr[o].ls)==k) {
        int pre=tr[o].ls;
        tr[o].ls=0;
        Pushup(o);
        return make_pair(pre,o);
    }
    if(Sz(tr[o].ls)+1==k) {
        int pre=tr[o].rs;
        tr[o].rs=0;
        Pushup(o);
        return make_pair(o,pre);
    }
    if(Sz(tr[o].ls)>k) {
        pair<int,int>tmp=Split(tr[o].ls,k);
        tr[o].ls=tmp.second;
        Pushup(o);
        return make_pair(tmp.first,o);
    }
    pair<int,int>tmp=Split(tr[o].rs,k-Sz(tr[o].ls)-1);
    tr[o].rs=tmp.first;
    Pushup(o);
    return make_pair(o,tmp.second);
}
inline int Getsum(int o,int l,int r) {
    Pushdown(o);
    pair<int,int>tmp1=Split(o,r),tmp2=Split(tmp1.first,l-1);
    int res=tr[tmp2.second].sum;
    rt=Merge(Merge(tmp2.first,tmp2.second),tmp1.second);
    return res;
}
inline int Maxsum(int o) {
    return tr[o].mx;
}
inline int Build(int *v,int len) {
    tp=0;
    for(int i=1;i<=len;i++) {
        int now=Newnode(v[i]),lst=0;
        while(tp&&tr[stk[tp]].fix>tr[now].fix) {
            Pushup(stk[tp]);
            lst=stk[tp];
            stk[tp--]=0;
        }
        if(tp)
            tr[stk[tp]].rs=now;
        tr[now].ls=lst;
        stk[++tp]=now;
    }
    while(tp)
        Pushup(stk[tp--]);
    return stk[1];
}
inline void Insert(int o,int pos,int k) {
    Pushdown(o);
    for(int i=1;i<=k;i++)
        read(a[i]);
    int now=Build(a,k);
    pair<int,int>tmp=Split(o,pos);
    rt=Merge(Merge(tmp.first,now),tmp.second);
}
inline void Delete(int o,int l,int r) {
    Pushdown(o);
    pair<int,int>tmp1=Split(o,r),tmp2=Split(tmp1.first,l-1);
    Clear(tmp2.second);
    rt=Merge(tmp2.first,tmp1.second);
}
inline void Makesame(int o,int l,int r,int k) {
    Pushdown(o);
    pair<int,int>tmp1=Split(o,r),tmp2=Split(tmp1.first,l-1);
    Cover(tmp2.second,k);
    rt=Merge(Merge(tmp2.first,tmp2.second),tmp1.second);
}
inline void Reverse(int o,int l,int r) {
    Pushdown(o);
    pair<int,int>tmp1=Split(o,r),tmp2=Split(tmp1.first,l-1);
    Revnode(tmp2.second);
    rt=Merge(Merge(tmp2.first,tmp2.second),tmp1.second);
}
inline void Print(int o) {
    if(!o)
        return;
    Print(tr[o].ls);
    printf("%d ",tr[o].val);
    Print(tr[o].rs);
}
int main() {
    int n,m;
    read(n);read(m);
    Insert(rt,0,n);
    while(m--) {
        char op[100];
        scanf("%s",op);
        if(op[0]=='G') {
            int l,r;
            read(l),read(r);
            printf("%d\n",Getsum(rt,l,l+r-1));
        }
        if(op[0]=='I') {
            int pos,tot;
            read(pos),read(tot);
            Insert(rt,pos,tot);
        }
        if(op[0]=='M') {
            if(op[2]=='X')
                printf("%d\n",Maxsum(rt));
            if(op[2]=='K') {
                int pos,tot,c;
                read(pos),read(tot),read(c);
                Makesame(rt,pos,pos+tot-1,c);
            }
        }
        if(op[0]=='D') {
            int pos,tot;
            read(pos),read(tot);
            Delete(rt,pos,pos+tot-1);
        }
        if(op[0]=='R') {
            int pos,tot;
            read(pos),read(tot);
            Reverse(rt,pos,pos+tot-1);
        }
//      puts("=====Check it:=====");
//      Print(rt);
    }
}

你可能感兴趣的:(无旋Treap)