• HDU 3436:splay tree


    给一个1~n的序列,有三种操作:

    1.TOP x :把x移到序列首部

    2.Query x:询问x的位置

    3.Rank x:询问第k个位置的元素

    总而言之就是一个序列维护的问题,用splay tree可以解决。但是首先要解决的问题就是把题目中的操作转化为splay tree的基本操作

    1. Top x:可以理解为把序列中的x找到并删除,然后再插入到序列首部

    2.Query x:找到x在树中的位置并输出其在序列中的位置

    3.Rank x:在树中找到维护的第x个数并输出

    常规来说,我们是在splay tree中一个结点维护原序列中的一个数,但是这里n有10^8,数组是开不下的,但是q只有10^5,我们可以想想如何离散化

    这里是把query 和top对应的x单独维护,其余部分作为一个区间放置进一个结点,这样可以保证结点数在10^5内

    为什么要这样做呢?首先对于top来说,我们是要做的是删除和插入操作,这里的操作对象只有x一个值,所以单独列出以免影响序列其他部分

    再一个就是query操作,我们查询位置的话在splay tree中的操作往往就是把x旋转到树根,那左子树的大小也就对应了x的在原序列的下标。如果x不是单独列出,那这一条定律显然是不成立的

    至于Rank,就相当于是在从左往右数数咯,可以一段一段数~~

    #include"cstdio"
    #include"queue"
    #include"cmath"
    #include"stack"
    #include"iostream"
    #include"algorithm"
    #include"cstring"
    #include"queue"
    #include"map"
    #include"vector"
    #define ll long long
    #define mems(a,b) memset(a,b,sizeof(a))
    
    using namespace std;
    const int MAXN = 200500;
    const int MAXE = 200500;
    const int INF = 0x3f3f3f;
    
    int pre[MAXN],ch[MAXN][2],siz[MAXN],num[MAXN],key[MAXN],ask[MAXN],p[MAXN],e[MAXN],s[MAXN];
    int root,tot,tail,n,P=1,cnt,T,q;
    
    struct Node{
        char op;
        int x;
    }node[MAXN];
    
    void pushup(int x){
        siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+num[x];
    }
    
    void init(){
        tot=0;
        root=0;
        cnt=0;
        tail=0;
        siz[0]=pre[0]=ch[0][0]=ch[0][1]=0;
    }
    
    void newnode(int &pos,int fa,int k){///k是在原数列(离散化后)中的位置,pos为在splay tree中的结点编号
        pos=++tot;
        pre[pos]=fa;
        p[k]=pos;           ///p[原序列位置]=树中位置
        key[pos]=k;         ///key[树中位置]=原序列中位置
        ch[pos][0]=ch[pos][1]=0;
        siz[pos]=num[pos]=e[k]-s[k]+1;
    }
    
    void build(int &x,int l,int r,int fa){
        if(l>r) return;
        int mid=(l+r)>>1;
        newnode(x,fa,mid);
        build(ch[x][0],l,mid-1,x);
        build(ch[x][1],mid+1,r,x);
        pushup(x);
    }
    
    void Rotate(int x,int kind){
        int fa=pre[x];
        ch[fa][!kind]=ch[x][kind];
        pre[ch[x][kind]]=fa;
        if(pre[fa]) ch[pre[fa]][ch[pre[fa]][1]==fa]=x;
        pre[x]=pre[fa];
        ch[x][kind]=fa;
        pre[fa]=x;
        pushup(fa);
    }
    
    int get_pos(int w){         ///找到w所在结点在原序列中的位置
        int low=0,high=cnt-1,mid;
        while(low<=high){
            mid=(low+high)>>1;
            if(s[mid]<=w&&w<=e[mid]) return mid;
            else if(w<s[mid]) high=mid-1;
            else low=mid+1;
        }
    }
    
    void Splay(int r,int goal){
        while(pre[r]!=goal){
            if(pre[pre[r]]==goal) Rotate(r,ch[pre[r]][0]==r);
            else{
                int fa=pre[r];
                int kind=(ch[pre[fa]][0]==fa);
                if(ch[fa][kind]==r){
                    Rotate(r,!kind);
                    Rotate(r,kind);
                }
                else{
                    Rotate(fa,kind);
                    Rotate(r,kind);
                }
            }
        }
        pushup(r);
        if(!goal) root=r;
    }
    
    void Insert(int &r,int fa,int k){///写成递归式为了pushup
        if(!r){
            newnode(r,fa,k);
            return;
        }
        else{
            Insert(ch[r][0],r,k);
            pushup(r);
        }
    }
    
    int getmax(int x){
        while(ch[x][1]) x=ch[x][1];
        return x;
    }
    
    void del(int x){
        Splay(x,0);
        if(!ch[root][0]){
            root=ch[root][1];
            pre[root]=0;
        }
        else{
            int t=getmax(ch[root][0]);
            Splay(t,root);
            ch[t][1]=ch[root][1];
            pre[ch[root][1]]=t;
            root=t;
            pre[root]=0;
            pushup(root);
        }
    }
    
    int get_kth(int r,int k){
        int lst=siz[ch[r][0]];
        if(k<=lst) return get_kth(ch[r][0],k);
        else if(k<=lst+num[r]) return s[key[r]]+(k-lst)-1;
        else return get_kth(ch[r][1],k-lst-num[r]);
    }
    
    void Top(int x){
        int k=get_pos(x);
        del(p[k]);
        Insert(root,0,k);
        Splay(tot,0);       ///这是以防该节点会在后面又被用到,这样可以保证各项操作均摊复杂度在log(n)~ORZZZZZZZZ
    }
    
    void Query(int x){
        int k=get_pos(x);
        Splay(p[k],0);
        printf("%d
    ",1+siz[ch[p[k]][0]]);
    }
    
    void Rank(int x){
        printf("%d
    ",get_kth(root,x));
    }
    
    int main(){
        //freopen("in.txt","r",stdin);
        scanf("%d",&T);
        while(T--){
            printf("Case %d:
    ",P++);
            scanf("%d%d",&n,&q);
            init();
    
            ask[tail++]=0;
            for(int i=0;i<q;i++){
                char arr[10];
                scanf("%s %d",arr,&node[i].x);
                node[i].op=arr[0];
                if(arr[0]=='T'||arr[0]=='Q') ask[tail++]=node[i].x;
            }
            ask[tail++]=n;
            sort(ask,ask+tail);
            for(int i=1;i<tail;i++){
                if(ask[i]!=ask[i-1]){
                    if(ask[i]-ask[i-1]>1){
                        s[cnt]=ask[i-1]+1;
                        e[cnt++]=ask[i]-1;
                    }
                    s[cnt]=e[cnt]=ask[i];
                    cnt++;
                }
            }
            build(root,0,cnt-1,0);
            for(int i=0;i<q;i++){
                if(node[i].op=='T') Top(node[i].x);
                else if(node[i].op=='Q') Query(node[i].x);
                else Rank(node[i].x);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Mongodb在windows下的安装和启动
    git操作的常用命令
    删除smartygit的配置文件
    注册树模式
    关于js的一些基础知识点
    关于mysql的初步学习 (五)
    关于mysql的初步学习 (四)
    关于mysql的初步学习 (三)
    关于mysql的初步学习 (二)
    关于数据库建表时的有趣实例--关键字重复
  • 原文地址:https://www.cnblogs.com/luxiaoming/p/5134653.html
Copyright © 2020-2023  润新知