无旋Treap——从入门到放弃

前言

已经是从入门到放弃的第四篇了。
但是本文并不打算给大家讲无旋Treap复杂度证明一类的。
很显然每次操作都是期望 Olog(n)

什么是Treap?

Treap=Tree+heap
其核心思想在于在权值上维护一棵二叉查找树,在优先级上维护一个堆
有旋treap利用旋转操作来维护堆的性质,
而无旋treap利用有序构树维护堆的性质。

无旋Treap的两大构树顺序:权值与原排列

权值构树是很常见的一种构树方法。和有旋treap一样,左儿子与右儿子分别表示比自己小或比自己大的树,同时其优先级均低于该节点。这类问题用有旋treap也能够很好地解决。这样的题有很多,比如bzoj3224普通平衡树
但很不幸的是,很多与平衡树沾边的题目大多有维护一个原有有序序列的要求,这个要求基本上就把有旋treap干掉了。但是对于无旋treap,我们可以按原有的序列进行构树,这样就可以维护一个原有的有序排列了。

无旋treap的核心操作:split与merge

但是在构树之后肯定是有修改操作的。这点是毋庸置疑的。对于有旋treap,我们可以通过旋转来插入要加入的权值或是删除对应的节点,但对于可能需要进行区间操作的无旋treap,我们显然不能直接这样做。
此时,因为无旋treap的有序性,我们可以像一般的有旋treap一样对需要
插入/删除的部分进行定位查找。
如果是对于权值有序,像普通的有旋treap一样直接递归查找即可,
如果是对于原序列有序,则维护一组指针,也可以很方便地进行查询。
那么在查询到了相应的树中位置之后,我们需要做的就是——
把这棵树拆开

split

整个无旋treap的核心就是它的有序性。
在找到了需要操作的位置后,我们可以把这棵树拆成两棵有序的树。
对于查询到的节点,我们根据该节点左儿子的大小对这个节点应该在哪棵树进行判断,然后递归处理即可。

inline D split(Treap* pos,int k){
    if(pos==NULL) return D(NULL,NULL);
    D y;
    if(sze(pos->son[0])>=k){
        y=split(pos->son[0],k);
        pos->son[0]=y.second;
        pos->update();
        y.second=pos;
    }else{
        y=split(pos->son[1],k-1-sze(pos->son[0]));
        pos->son[1]=y.first;
        pos->update();
        y.first=pos;
    }
    return y;
}

merge

在你进行了加入/删除操作之后,你发现你手上现在有两到三棵树了,自然我们需要将这些树合并。合并的具体操作也是递归处理,此时就可以维护无旋treap的堆性质。
但是需要注意的是,合并时两棵树的左右位置,维护的是整棵树的有序性。

inline Treap* merge(Treap* a,Treap* b){
    if(!a) return b;
    if(!b) return a;
    if(a->weightweight){
        a->son[1]=merge(a->son[1],b);
        a->update();
        return a;
    }else{
        b->son[0]=merge(a,b->son[0]);
        b->update();
        return b;
    }
}

水得如壶口瀑布一样的水题

(1)bzoj3224:普通平衡树
题面见链接 传送门
最简单最基础的权值排序外加单点修改查询

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read(){
    int i=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())
        if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar())
        i=(i<<3)+(i<<1)+(ch^48);
    return i*f;
}
int buf[1024];
inline void write(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x){buf[++buf[0]]=x%10,x/=10;}
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}
struct Treap{
    Treap* son[2];
    int weight,sze,data;
    Treap(int v){
        sze=1,data=v;weight=rand();
        son[1]=son[0]=NULL;
        return ;
    }
    inline void update(){
        sze=1+(son[0]!=NULL?son[0]->sze:0)+(son[1]!=NULL?son[1]->sze:0);
        return ;
    }
}*root;
typedef pair*,Treap*>D;
inline int sze(Treap* pos){
    return pos?pos->sze:0;
}
int n,ord,x;
inline Treap* merge(Treap* a,Treap* b){
    if(!a) return b;
    if(!b) return a;
    if(a->weightweight){
        a->son[1]=merge(a->son[1],b);
        a->update();
        return a;
    }else{
        b->son[0]=merge(a,b->son[0]);
        b->update();
        return b;
    }
}
inline D split(Treap* pos,int k){
    if(pos==NULL) return D(NULL,NULL);
    D y;
    if(sze(pos->son[0])>=k){
        y=split(pos->son[0],k);
        pos->son[0]=y.second;
        pos->update();
        y.second=pos;
    }else{
        y=split(pos->son[1],k-1-sze(pos->son[0]));
        pos->son[1]=y.first;
        pos->update();
        y.first=pos;
    }
    return y;
}
inline int getrank(Treap* pos,int x){
    if(pos==NULL) return 0;
    else return (pos->data>=x)?getrank(pos->son[0],x):getrank(pos->son[1],x)+1+sze(pos->son[0]);
}
inline int getkth(int k){
    D x=split(root,k-1);
    D y=split(x.second,1);
    Treap* pos=y.first;
    root=merge(x.first,merge(pos,y.second));
    return pos==NULL?0:pos->data;
}
inline void insert(int d){
    int k=getrank(root,d);
    D x=split(root,k);
    Treap* pos=new Treap(d);
    root=merge(x.first,merge(pos,x.second));
    return ;
}
inline void remove(int d){
    int k=getrank(root,d);
    D x=split(root,k);
    D y=split(x.second,1);
    root=merge(x.first,y.second);
    return ;
}
signed main(){
    n=read();
    for(int i=1;i<=n;++i){
        ord=read();x=read();
        switch(ord){
            case 1:insert(x);break;
            case 2:remove(x);break;
            case 3:write(getrank(root,x)+1);puts("");break;
            case 4:write(getkth(x));puts("");break;
            case 5:write(getkth(getrank(root,x)));puts("");break;
            case 6:write(getkth(getrank(root,x+1)+1));puts("");break;
        }
    }
    return 0;
}

(2)bzoj1503 郁闷的出纳员
题面依然见链接点这里
很明显你不能直接进行全局修改对伐。这个时候你需要打一个差分。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read(){
    int i=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())
        if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar())
        i=(i<<3)+(i<<1)+(ch^48);
    return i*f;
}
int buf[1024];
inline void write(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x){buf[++buf[0]]=x%10,x/=10;}
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}
#define stan 11
struct Treap{
    Treap* son[2];
    int sze,val,weight;
    Treap(){val=sze=0,weight=rand();son[1]=son[0]=NULL;}
    inline void update(){
        sze=1+son[0]->sze+son[1]->sze;
    }
}*null=new Treap,*root=null;
typedef pair*,Treap*> D;
int m,mini,tmp=0,x,cnt;
char ord[stan];
inline Treap* newtreap(int x){
    Treap* pos=new Treap();
    pos->son[0]=pos->son[1]=null;
    pos->sze=1;pos->val=x;
    return pos;
}
inline Treap* merge(Treap* a,Treap* b){
    if(a==null) return b;
    if(b==null) return a;
    if(a->weightweight){
        a->son[1]=merge(a->son[1],b);
        a->update();
        return a;
    }else{
        b->son[0]=merge(a,b->son[0]);
        b->update();
        return b;
    }
}
inline D split(Treap* pos,int k){
    if(pos==null) return D(null,null);
    D y;
    if(pos->son[0]->sze>=k){
        y=split(pos->son[0],k);
        pos->son[0]=y.second;
        pos->update();
        y.second=pos;
    }else{
        y=split(pos->son[1],k-1-pos->son[0]->sze);
        pos->son[1]=y.first;
        pos->update();
        y.first=pos;
    }
    return y;
}
inline int getrank(Treap* pos,int x){
    if(pos==null) return 0;
    return (pos->val>=x)?getrank(pos->son[0],x):getrank(pos->son[1],x)+1+pos->son[0]->sze;
}
inline int getkth(int k){
    D x=split(root,k-1);
    D y=split(x.second,1);
    Treap* pos=y.first;
    root=merge(x.first,merge(pos,y.second));
    return pos->val;
}
inline void insert(int d){
    int k=getrank(root,d);
    D x=split(root,k);
    Treap* pos=newtreap(d);
    root=merge(x.first,merge(pos,x.second));
    return ;
}
inline void remove(){
    D x=split(root,1);
    root=x.second;
    ++cnt;
    return ;
}
signed main(){
    m=read();mini=read();
    while(m--){
        scanf("%s",ord);x=read();
        switch(ord[0]){
            case 'I':if(x>=mini) insert(x-tmp);break;
            case 'F':{
                if(root==null||root->sze<x)
                    puts("-1");
                else{
                    write(getkth(root->sze-x+1)+tmp);
                    puts("");
                }
                break;
            }
            case 'A':tmp+=x;break;
            case 'S':{
                tmp-=x;
                while(root!=null&&getkth(1)+tmpbreak;
            }
        }
    }
    write(cnt);
    return 0;
}

(3)bzoj3223文艺平衡树
题面照例见链接点我点我
基础的区间翻转操作,像线段树一样打标记即可

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read(){
    int i=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())
        if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar())
        i=(i<<3)+(i<<1)+(ch^48);
    return i*f;
}
int buf[1024];
inline void write(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x){buf[++buf[0]]=x%10,x/=10;}
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}
#define stan 555555
struct Treap{
    Treap* son[2];
    int val,weight,sze;bool flip; 
    Treap(){
        val=-999999999;sze=0;weight=rand();flip=false;
        return ;
    }
    inline void update(){
        sze=son[1]->sze+son[0]->sze+1;
        return ;
    }
}*null=new Treap(),*root=null,*stack[stan],*x,*last;
typedef pair*,Treap*> D;
int n,m,sta,en;
inline void maintain_flip(Treap* pos){
    if(pos==null) return ;
    pos->flip^=1;
    return ;
}
inline void pushdown(Treap* pos){
    if(pos==null) return ;
    if(pos->flip){
        pos->flip^=1;
        maintain_flip(pos->son[0]);
        maintain_flip(pos->son[1]);
        swap(pos->son[0],pos->son[1]);
    }
    return ;
}
inline Treap* newtreap(int val){
    Treap *pos=new Treap();
    pos->son[1]=pos->son[0]=null;pos->weight=rand();
    pos->val=val;pos->sze=1;pos->flip=0;
    return pos;
}
inline Treap* merge(Treap* a,Treap* b){
    if(a==null) return b;
    if(b==null) return a;
    pushdown(a);pushdown(b);
    if(a->weightweight){
        a->son[1]=merge(a->son[1],b);
        a->update();
        return a;
    }else{
        b->son[0]=merge(a,b->son[0]);
        b->update();
        return b;
    }
}
inline D split(Treap* pos,int k){
    if(pos==null) return D(null,null);
    D y;pushdown(pos);
    if(pos->son[0]->sze>=k){
        y=split(pos->son[0],k);
        pos->son[0]=y.second;
        pos->update();
        y.second=pos;
    }else{
        y=split(pos->son[1],k-1-pos->son[0]->sze);
        pos->son[1]=y.first;
        pos->update();
        y.first=pos;
    }
    return y;
}
inline Treap* build(){
    int p=0;
    for(int i=1;i<=n;++i){
        x=newtreap(i);last=null;
        while(p&&stack[p]->weight>x->weight){
            stack[p]->update();
            last=stack[p];
            stack[p--]=null;
        }
        if(p) stack[p]->son[1]=x;
        x->son[0]=last;stack[++p]=x;
    }
    while(p) stack[p--]->update();
    return stack[1];
}
inline void reverse(){
    sta=read();en=read();
    D x=split(root,sta-1);
    D y=split(x.second,en-sta+1);
    maintain_flip(y.first);
    root=merge(x.first,merge(y.first,y.second));
    return ;
}
inline void write_in_order(Treap* pos){
    if(pos==null) return;
    pushdown(pos);
    write_in_order(pos->son[0]);
    write(pos->val);putchar(' ');
    write_in_order(pos->son[1]);
    return ;
}
signed main(){
    n=read();m=read();
    root=build();
    while(m--) reverse();
    write_in_order(root); 
    return 0;
}

(4)ZJOI2006书架
题面还是点链接吧http://www.lydsy.com/JudgeOnline/problem.php?id=1861
这个地方也是很正常的单点修改,不过注意一下合并的顺序即可

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read(){
    int i=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())
        if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar())
        i=(i<<3)+(i<<1)+(ch^48);
    return i*f;
}
int buf[1024];
inline void write(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x){buf[++buf[0]]=x%10,x/=10;}
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}
typedef unsigned int uint;
inline uint nextUint() {
    static uint seed = 19260817;
    seed ^= seed << 13;
    seed ^= seed >> 17;
    seed ^= seed << 5;
    return seed;
}
#define stan 88888
#define sten 11
struct Treap{
    Treap* son[2];
    Treap* fa;
    int sze,val;
    uint weight;
    Treap(){val=-999999999,sze=0,weight=nextUint(),son[0]=son[1]=fa=this;}
    inline void update(){
        sze=son[0]->sze+son[1]->sze+1;
        son[0]->fa=son[1]->fa=this;
    }
}*null=new Treap(),*root=null,*stack[stan],*x,*last,*posi[stan];
typedef pair*,Treap*> D;
int n,m,s,u,a[stan];
char ord[sten];
inline Treap* newtreap(int val){
    Treap* pos=new Treap();
    pos->son[1]=pos->son[0]=pos->fa=null;
    pos->sze=1;pos->val=val;pos->weight=nextUint();
    return pos;
}
inline Treap* merge(Treap* a,Treap* b){
    if(a==null) return b;
    if(b==null) return a;
    if(a->weightweight){
        a->son[1]=merge(a->son[1],b);
        a->update();
        return a;
    }else{
        b->son[0]=merge(a,b->son[0]);
        b->update();
        return b;
    }
}
inline D split(Treap* pos,int k){
    if(pos==null) return D(null,null);
    D y;
    if(pos->son[0]->sze>=k){
        y=split(pos->son[0],k);
        pos->son[0]=y.second;
        pos->update();
        y.second=pos;
    }else{
        y=split(pos->son[1],k-1-pos->son[0]->sze);
        pos->son[1]=y.first;
        pos->update();
        y.first=pos;
    }
    return y;
}
inline Treap* build(){
    int p=0;
    for(int i=1;i<=n;++i){
        a[i]=read();
        posi[a[i]]=x=newtreap(a[i]);last=null;
        while(p&&stack[p]->weight>x->weight){
            stack[p]->update();
            last=stack[p];
            stack[p--]=null;
        }
        if(p) stack[p]->son[1]=x;x->fa=stack[p];
        x->son[0]=last;last->fa=x;
        stack[++p]=x;
    }
    while(p) stack[p--]->update();
    return stack[1];
}
inline int getrank(Treap* pos){
    int ret=pos->son[0]->sze;
    while(pos->fa!=null&&pos->fa!=NULL){
        if(pos==pos->fa->son[1]) ret+=pos->fa->son[0]->sze+1;
        pos=pos->fa;
    }
    return ret;
}
inline void addhead(int x){
    int k=getrank(posi[x]);
    D X=split(root,k);
    D y=split(X.second,1);
    root=merge(y.first,merge(X.first,y.second));
    return ;
}
inline void addtail(int x){
    int k=getrank(posi[x]);
    D X=split(root,k);
    D y=split(X.second,1);
    root=merge(X.first,merge(y.second,y.first));
    return ;
}
void addmid(int xxx,int opt) {  
    if(!opt) return ;
    static D X,y,z;  
    int k=getrank(posi[xxx]);  
    X=split(root, k);  
    y=split(X.second,1);  
    if(opt==-1)X=split(X.first,X.first->sze-1), root=merge(merge(X.first,y.first),merge(X.second,y.second));  
    else z=split(y.second,1), root=merge(merge(X.first,z.first),merge(y.first,z.second));  
}  
inline int getkth(int k){
    D X=split(root,k-1);
    D y=split(X.second,1);
    Treap* pos=y.first;
    root=merge(X.first,merge(pos,y.second));
    return pos->val;
}
signed main(){
    n=read();m=read();
    root=build();
    while(m--){
        scanf("%s",ord);s=read();
        switch(ord[0]){
            case 'T':addhead(s);break;
            case 'B':addtail(s);break;
            case 'I':u=read();addmid(s,u);break;
            case 'A':write(getrank(posi[s]));puts("");break;
            case 'Q':write(getkth(s));puts("");break;
        }
    }
    return 0;
}

(5)CQOI2014排序机械臂
题面还是有链接就是这里
很中规中矩的不固定排列序+区间修改

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read(){
    int i=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())
        if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar())
        i=(i<<3)+(i<<1)+(ch^48);
    return i*f;
}
int buf[1024];
inline void write(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x){buf[++buf[0]]=x%10,x/=10;}
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}
typedef unsigned int uint;
inline uint nxtunit(){
    static uint seed=19260817;
    seed^=seed<<13;
    seed^=seed>>17;
    seed^=seed<<5;
    return seed;
}
#define stan 111111
struct Treap{
    Treap* son[2];
    Treap* fa;
    int sze,val;
    uint weight;
    bool flip;
    Treap(){val=-999999999,sze=0,weight=nxtunit(),son[0]=son[1]=fa=this;flip=false;}
    inline void update(){
        sze=son[0]->sze+son[1]->sze+1;
        son[0]->fa=son[1]->fa=this;
    }
}*null=new Treap(),*root=null,*stack[stan],*x,*last,*posi[stan];
typedef pair*,Treap*> D;
int n,m,s,u,a[stan],to[stan];
struct thing{
    int ord,val;
}thi[stan];
inline bool cmp(const thing &a,const thing &b){
    if(a.val!=b.val) return a.valelse return a.ordord;
}
inline Treap* newtreap(int val){
    Treap* pos=new Treap();
    pos->son[1]=pos->son[0]=pos->fa=null;
    pos->sze=1;pos->val=val;pos->weight=nxtunit();
    pos->flip=false;
    return pos;
}
inline void pushdown(Treap* pos){
    if(pos==null||pos==NULL) return ;
    if(pos->flip){
        pos->flip^=1;
        pos->son[0]->flip^=1;
        pos->son[1]->flip^=1;
        swap(pos->son[0],pos->son[1]);
    }
    return ;
}
inline Treap* merge(Treap* a,Treap* b){
    if(a==null) return b;
    if(b==null) return a;
    pushdown(a);pushdown(b);
    if(a->weightweight){
        a->son[1]=merge(a->son[1],b);
        a->update();
        return a;
    }else{
        b->son[0]=merge(a,b->son[0]);
        b->update();
        return b;
    }
}
inline D split(Treap* pos,int k){
    if(pos==null) return D(null,null);
    D y;pushdown(pos);
    if(pos->son[0]->sze>=k){
        y=split(pos->son[0],k);
        pos->son[0]=y.second;
        pos->update();
        y.second=pos;
    }else{
        y=split(pos->son[1],k-1-pos->son[0]->sze);
        pos->son[1]=y.first;
        pos->update();
        y.first=pos;
    }
    return y;
}
inline void rotate(Treap* pos){
    if(pos==null||pos==NULL) return ;
    rotate(pos->fa);
    pushdown(pos);
    return ; 
}
inline int getrank(Treap* pos){
    rotate(pos);
    int ret=pos->son[0]->sze+1;
    while(pos->fa!=null&&pos->fa!=NULL){
        if(pos==pos->fa->son[1]) ret+=pos->fa->son[0]->sze+1;
        pos=pos->fa;
    }
    return ret;
}
inline int getans(int d){
    int ret=getrank(posi[d]);
    D x=split(root,ret);
    D y=split(x.first,d-1);
    y.second->flip^=1;
    root=merge(merge(y.first,y.second),x.second);
    return ret;
}
signed main(){
    n=read();
    for(int i=1;i<=n;++i){
        a[i]=read();thi[i].ord=i;thi[i].val=a[i];
    }
    sort(thi+1,thi+n+1,cmp);
    for(int i=1;i<=n;++i)
        to[thi[i].ord]=i;
    for(int i=1;i<=n;++i){
        posi[to[i]]=newtreap(a[i]);
        root=merge(root,posi[to[i]]);
    }
    for(int i=1;iwrite(getans(i));
        putchar(' ');
    }
    write(getans(n));
    return 0;
}

(6) NOI2005维修数列
题面在这里
如果你上面五道题都A了,这个题也不难想
写就是另一回事了

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read(){
    int i=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())
        if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar())
        i=(i<<3)+(i<<1)+(ch^48);
    return i*f;
}
int buf[1024];
inline void write(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x){buf[++buf[0]]=x%10,x/=10;}
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}
#define stan 555555
struct Treap{
    Treap* son[2];
    int val,weight,sze,sum,l,r,m;bool flip,mark; 
    Treap(){val=l=r=m=-999999999,sum=sze=0;mark=flip=0;weight=rand();}
    inline void update(){
        sze=son[1]->sze+son[0]->sze+1;
        sum=son[1]->sum+son[0]->sum+val;
        l=max(son[0]->l,max(son[0]->sum+val,son[0]->sum+val+son[1]->l));
        r=max(son[1]->r,max(son[1]->sum+val,son[1]->sum+val+son[0]->r));
        m=max(son[0]->m,max(max(0,son[0]->r)+val+max(0,son[1]->l),son[1]->m));
    }
}*null=new Treap(),*root=null,*stack[stan],*x,*last;
typedef pair*,Treap*> D;
int n,m,a[stan];
char ord[stan];
inline void maintain_flip(Treap* pos){
    if(pos==null) return ;
    pos->flip^=1;swap(pos->l,pos->r);
    return ;
}
inline void maintain_mark(Treap* pos,int c){
    if(pos==null) return ;
    pos->val=c;pos->sum=pos->sze*c;
    pos->l=pos->r=pos->m=max(pos->sze*c,c);
    pos->mark=true;
    return ;
}
inline void pushdown(Treap *pos){
    if(pos==null) return ;
    if(pos->flip){
        pos->flip^=1;
        maintain_flip(pos->son[0]);
        maintain_flip(pos->son[1]);
        swap(pos->son[0],pos->son[1]);
    }
    if(pos->mark){
        maintain_mark(pos->son[0],pos->val);
        maintain_mark(pos->son[1],pos->val);
        pos->mark=0;
    }
    return ;
}
inline Treap* newtreap(int val)
{
    Treap *pos=new Treap();
    pos->son[1]=pos->son[0]=null;pos->weight=rand();
    pos->val=pos->sum=val;pos->sze=1;pos->flip=pos->mark=0;
    pos->m=pos->l=pos->r=val;
    return pos;
}
Treap* merge(Treap* a,Treap* b){
    if(a==null) return b;
    if(b==null) return a;
    pushdown(a);pushdown(b);
    if(a->weightweight){
        a->son[1]=merge(a->son[1],b);
        a->update();
        return a;
    }else{
        b->son[0]=merge(a,b->son[0]);
        b->update();
        return b;
    }
}
D split(Treap* pos,int k){
    if(pos==null) return D(null,null);
    D y;pushdown(pos);
    if(pos->son[0]->sze>=k){
        y=split(pos->son[0],k);
        pos->son[0]=y.second;
        pos->update();
        y.second=pos;
    }else{
        y=split(pos->son[1],k-1-pos->son[0]->sze);
        pos->son[1]=y.first;
        pos->update();
        y.first=pos;
    }
    return y;
}
inline Treap* build(){
    int p=0;
    for(int i=1;i<=n;++i){
        a[i]=read();
        x=newtreap(a[i]);last=null;
        while(p&&stack[p]->weight>x->weight){
            stack[p]->update();
            last=stack[p];
            stack[p--]=null;
        }
        if(p) stack[p]->son[1]=x;
        x->son[0]=last;stack[++p]=x;
    }
    while(p) stack[p--]->update();
    return stack[1];
}
inline void adjust(Treap *pos){
    if(pos==null) return;
    if(pos->son[0]!=null) adjust(pos->son[0]);
    if(pos->son[1]!=null) adjust(pos->son[1]);
    delete pos;return ;
}
inline void insert(){
    int sta;sta=read();n=read();
    Treap* pos=build();
    D x=split(root,sta);
    root=merge(x.first,merge(pos,x.second));
    return ;
}
inline void remove(){
    int sta;sta=read();n=read();
    D x=split(root,sta-1);
    D y=split(x.second,n);
    adjust(y.first);
    root=merge(x.first,y.second);
    return ;
}
inline void reverse(){
    int sta;sta=read();n=read();
    D x=split(root,sta-1);
    D y=split(x.second,n);
    maintain_flip(y.first);
    root=merge(x.first,merge(y.first,y.second));
    return ;
}
inline void make_same(){
    int sta,c;sta=read();n=read();c=read();
    D x=split(root,sta-1);
    D y=split(x.second,n);
    maintain_mark(y.first,c);
    root=merge(x.first,merge(y.first,y.second));
    return ;
}
inline int get_sum(){
    int sta;sta=read();n=read();
    if(n==0) return 0;
    D x=split(root,sta-1);
    D y=split(x.second,n);
    int ret=y.first->sum;
    root=merge(x.first,merge(y.first,y.second));
    return ret;
}
signed main(){
    n=read();m=read();
    root=build();
    while(m--){
        scanf("%s",ord);
        switch(ord[0]){
            case 'I':{insert();break;}
            case 'D':{remove();break;}
            case 'M':{
                if(ord[2]=='K'){make_same();break;}
                else {write(root->m);puts("");break;}
            }
            case 'G':{write(get_sum());puts("");break;}
            case 'R':{reverse();break;}
        }
    } 
    return 0;
}

小结

终于是又水了一篇
其实我觉得LadyLex的讲解才是坠吼的传送门
%%%LadyLex
同时感谢Xehoth大佬在看到我在内网莫名血T之后甩给了我一个强大的随机数生成器
%%%Xehoth

你可能感兴趣的:(OI,平衡树纲)