ZJOI2006 书架 lg2596

题面见https://www.luogu.org/problemnew/show/P2596

题面就是描述了一个书柜从上到下放着书,可以看作一个序列,每个数的序号为它在从上向下数第几本

一开始建树偷了个懒,就直接一个个insert

因为题目中都是以书的编号进行操作,所以记一个pos[ ]

操作一:把pos[x] splay到根,左儿子都是比它编号小的,那么就把左儿子挂到根的后面,根+1的前面,具体怎么找这个点看代码解释

操作二:同一理

操作三:实际上只更改了x和x的前驱或后继的值,和他们代表的值的位置,只修改这两个标记即可

操作四:把pos[x] splay到根,左儿子都是比它编号小的,那么答案就是st[ls].size

操作五:常规查询第k大

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int w=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        w=(w<<3)+(w<<1)+ch-48;
        ch=getchar();
    }
    return w*f;
}
int n,m,cnt,tot,root,a[500010],pos[500010];
bool debug;
struct node{
    int val,ch[2],size,f;
}st[5000010];
inline void push_up(int x){
    int ls=st[x].ch[0];int rs=st[x].ch[1];
    st[x].size=st[ls].size+st[rs].size+1;
    pos[st[ls].val]=ls;pos[st[rs].val]=rs;
}
inline bool identify(int p){
    return st[st[p].f].ch[1]==p;
}
inline void connect(int x,int fa,int son){
    st[x].f=fa;st[fa].ch[son]=x;return;
}
inline void rotate(int x){
    int y=st[x].f;int z=st[y].f;
    int yson=identify(x);int zson=identify(y);
    int b=st[x].ch[yson^1];
    connect(b,y,yson);connect(y,x,(yson^1));connect(x,z,zson);
    push_up(y);push_up(x);if(z)push_up(z);return;
}
inline void splay(int x,int goal){
    while(st[x].f!=goal){
        int y=st[x].f;int z=st[y].f;
        int yson=identify(x);int zson=identify(y);
        if(z!=goal){
            if(yson==zson) rotate(y);
            else rotate(x);
        }
        rotate(x);
    }
    if(!goal) root=x;
    return;
}//这以上都是常规操作 
inline void insert(int x){
    cnt++;int now=cnt;st[now].size=1;
    st[now].val=x;pos[x]=now;st[now].ch[0]=st[now].ch[1]=0;
    if(cnt>1){//只要当前节点不是根,都要将它和父亲连一下,并splay到根 
        st[now].f=now-1;st[now-1].ch[1]=now;
        splay(now,0);
    }
}//建树操作 

inline void output(int x){
    int ls=st[x].ch[0];int rs=st[x].ch[1];
    if(ls) output(ls);
    printf("%d ",st[x].val);
    if(rs) output(rs);
    return;
}//输出整颗区间树,debug用的 

inline int find(int p,int rk){
    int ls=st[p].ch[0];int rs=st[p].ch[1];
    if(st[ls].size+1==rk) return p;
    if(st[ls].size>=rk) return find(ls,rk);
    return find(rs,rk-st[ls].size-1);
}//找树上排名 

inline void Top(int x){
    x=pos[x];splay(x,0);
    if(!st[x].ch[0]) return;//如果没有左儿子就不用管了 
    if(!st[x].ch[1]){//没有右儿子就把左儿子挂过去就完事了 
        st[x].ch[1]=st[x].ch[0];st[x].ch[0]=0;return;
    }
    int ls=st[x].ch[0];
    int y=find(root,st[ls].size+2);//根的rank是st[ls].size+1,st[ls].size+2为根的后继 
    st[ls].f=y;st[y].ch[0]=ls;//根的左子树应该挂在根的后继的左子树 
    st[x].ch[0]=0;splay(y,0);//最后把更改的点splay到根 
    return;
}
inline void Bottom(int x){//操作同上,反向操作即可 
    x=pos[x];splay(x,0);
    if(!st[x].ch[1]) return;
    if(!st[x].ch[0]){
        st[x].ch[0]=st[x].ch[1];st[x].ch[1]=0;return;
    }
    int ls=st[x].ch[0];int rs=st[x].ch[1];
    int y=find(root,st[ls].size);
    st[rs].f=y;st[y].ch[1]=rs;
    st[x].ch[1]=0;splay(y,0);
    return;
}

inline void change(int x,int y){//题目中的insert操作 
    x=pos[x];splay(x,0);if(!y) return;//如果y==0,说明就不用修改 
    int ls=st[x].ch[0];
    if(y==-1){//y==-1就找前驱 
        y=find(root,st[ls].size);
    }
    else y=find(root,st[ls].size+2);//y==1就找后缀 
    swap(pos[st[x].val],pos[st[y].val]);//这要修改两个点的值和两个点值的所在位置 
    swap(st[x].val,st[y].val);return;
}

inline void rnk(int x){//常规查排名操作 
    x=pos[x];splay(x,0);
    int ls=st[x].ch[0];
    printf("%d\n",st[ls].size);return;
}

inline void kth(int x){//常规排名找点操作 
    x=find(root,x);
    printf("%d\n",st[x].val);return;
}

int main(){
    n=read();m=read();int i,j,k;root=1;
    for(i=1;i<=n;i++){
        int x=read();insert(x);
    }
    //debug=true;
    while(m--){
        string s;cin>>s;int x,y;
        if(s[0]=='T'){
            x=read();Top(x);
        }
        if(s[0]=='B'){
            x=read();Bottom(x);
        }
        if(s[0]=='I'){
            x=read();y=read();change(x,y);
        }
        if(s[0]=='A'){
            x=read();rnk(x);
        }
        if(s[0]=='Q'){
            x=read();kth(x);
        }
        if(debug){
            cout<<"debuging";
            output(root);
            cout<<endl;
        }
    }
    return 0;
}

 

posted @ 2018-12-19 10:42  温词  阅读(91)  评论(0编辑  收藏  举报