zoukankan      html  css  js  c++  java
  • 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
    ",st[ls].size);return;
    }
    
    inline void kth(int x){//常规排名找点操作 
        x=find(root,x);
        printf("%d
    ",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;
    }
  • 相关阅读:
    如何实现浏览器内多个标签页之间的通信?
    vue组件库的基本开发步骤(源代码)
    vue组件库的基本开发步骤
    Websocket原理
    TCP和UDP的区别
    一句话概括 tcp三次握手
    简单说一下你对http和https的理解
    .Ajax(async异步与sync同步)
    get和post请求方式的区别
    面试易忽略状态码
  • 原文地址:https://www.cnblogs.com/wenci/p/10141808.html
Copyright © 2011-2022 走看看