【Luogu】P2596书架(Splay)

  题目链接

  通过这题我加深了对Splay的理解,原来Splay的子树也是可以接来接去接到别的点上的,而不是只能旋转qwq

  具体接的办法就是swap大法。

  对于Top操作我们把当前节点Splay到根,然后把它的左子树接到后继上。

  Bottom同理

  对于Insert,暴力swap当前节点和它的前驱或者后继。

  Ask操作就把节点Splay到根,然后输出它的左子树有多少节点。

  Query直接查就行。

  

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cstdlib>
#define maxn 1000010
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int pos[maxn];
int CNT=0;
struct Splay{
    struct Node{
        int key,val,fa,e[2],size;
    }tree[maxn];
    int tag[maxn];
    int point,tot,root;
    Splay(){point=tot=root=0;memset(tag,0,sizeof(tag));    }
    inline void update(int x){    tree[x].size=tree[tree[x].e[0]].size+tree[tree[x].e[1]].size+1;    }
    inline void connect(int x,int fa,int how){    tree[x].fa=fa;    tree[fa].e[how]=x;    }
    inline int iden(int x){    return x==tree[tree[x].fa].e[1];    }
    inline void rotate(int x){
        int y=tree[x].fa;int r=tree[y].fa;
        if(y==root)    root=x;
        int sony=iden(x);int sonr=iden(y);
        int b=tree[x].e[sony^1];
        connect(b,y,sony);
        connect(y,x,sony^1);
        connect(x,r,sonr);
        update(y);    update(x);
    }
    void splay(int pos,int to){
        to=tree[to].fa;
        while(tree[pos].fa!=to){
            if(tree[tree[pos].fa].fa==to)    rotate(pos);
            else
                if(iden(pos)==iden(tree[pos].fa)){
                    rotate(tree[pos].fa);
                    rotate(pos);
                }
                else{    rotate(pos);    rotate(pos);    }
        }
    }
    int create(int key,int val,int fa){
        tree[++tot].val=val;    tree[tot].fa=fa;
        tree[tot].size=1;    tree[tot].key=key;
        return tot;
    }
    int build(int key,int val){
        if(root==0){    root=create(key,val,0);    return root;    }
        int now=root;
        while(1){
            tree[now].size++;
            int nxt=tree[now].key>key?0:1;
            if(tree[now].e[nxt]==0){
                connect(create(key,val,now),now,nxt);
                return tot;
            }
            now=tree[now].e[nxt];
        }
    }
    void insert(int key,int val){
        int p=build(key,val);
        pos[val]=p;
        if(++CNT=50){
            CNT=0;
            splay(p,root);
        }
    }
    int find(int rnk){
        int now=root;
        while(now){
            if(tree[tree[now].e[0]].size+1==rnk)    return now;
            else if(tree[tree[now].e[0]].size>=rnk)    now=tree[now].e[0];
            else{
                rnk-=tree[tree[now].e[0]].size+1;
                now=tree[now].e[1];
            }
        }
    }
    void rotop(int val){
        val=pos[val];
        splay(val,root);
        int le=tree[val].e[0];
        if(le==0)    return;
        if(tree[val].e[1]==0){
            connect(le,val,1);
            tree[val].e[0]=0;
            update(val);
        }
        else{
            int deal=find(tree[tree[val].e[0]].size+2);
            connect(tree[val].e[0],deal,0);    tree[val].e[0]=0;
            int now=deal;
            while(now){
                update(now);
                now=tree[now].fa;
            }
            splay(deal,root);
        }
    }
    void roend(int val){
        val=pos[val];
        splay(val,root);
        int ri=tree[val].e[1];
        if(ri==0)    return;
        if(tree[val].e[0]==0){
            connect(ri,val,0);
            tree[val].e[1]=0;
            update(val);
        }
        else{
            int deal=find(tree[tree[val].e[0]].size);
            connect(tree[val].e[1],deal,1);    tree[val].e[1]=0;
            int now=deal;
            while(now){
                update(now);
                now=tree[now].fa;
            }
            splay(deal,root);
        }
    }
    void rofro(int val){
        val=pos[val];
        splay(val,root);
        int deal=find(tree[tree[val].e[0]].size);
        std::swap(pos[tree[val].val],pos[tree[deal].val]);
        std::swap(tree[val].val,tree[deal].val);
    }
    void rosub(int val){
        val=pos[val];
        splay(val,root);
        int deal=find(tree[tree[val].e[0]].size+2);
        std::swap(pos[tree[val].val],pos[tree[deal].val]);
        std::swap(tree[val].val,tree[deal].val);
    }
    int rank(int key){
        int now=root;
        while(now){
            if(tree[tree[now].e[0]].size+1==key)    return tree[now].val;
            if(tree[tree[now].e[0]].size>=key)    now=tree[now].e[0];
            else{
                key-=tree[tree[now].e[0]].size+1;
                now=tree[now].e[1];
            }
        }
        return 0;
    }
    int arank(int val){
        val=pos[val];
        splay(val,root);
        return tree[tree[val].e[0]].size;
    }
}s;

int main(){
    int n=read(),m=read();
    for(int i=1;i<=n;++i){
        int x=read();
        s.insert(i,x);
    }
    for(int i=1;i<=m;++i){
        char c[10];int x;
        scanf("%s%d",c,&x);
        switch(c[0]){
            case 'T':{
                s.rotop(x);
                break;
            }
            case 'B':{
                s.roend(x);
                break;
            }
            case 'I':{
                int y=read();
                if(y==-1)    s.rofro(x);
                if(y==1)    s.rosub(x);
                break;
            }
            case 'A':{
                printf("%d\n",s.arank(x));
                break;
            }
            case 'Q':{
                printf("%d\n",s.rank(x));
                break;
            }
        }
    }
    return 0;
}

 

posted @ 2018-01-16 20:12  Konoset  阅读(204)  评论(0编辑  收藏  举报