zoukankan      html  css  js  c++  java
  • treap

    treap

    您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:插入x数,删除x数(若有多个相同的数,因只删除一个),查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名),查询排名为x的数,求x的前驱(前驱定义为小于x,且最大的数),求x的后继(后继定义为大于x,且最小的数)。

    treap似乎就是一个保持堆性质的二叉搜索树。结点的优先级是随机分配的。可以保证treap的所有操作,期望时间复杂度都为logn。

    代码中大量运用了递归操作。注意一个坑点是删除操作的最后需要update一下。

    #include <ctime>
    #include <cctype>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    
    const int maxn=1e5+5, INF=1e9;
    int randint(){  //比手写rand效果好
        return rand();
    }
    
    void get(int &x){
        static int flag; static char c; flag=1;  //static的变量只初始化一次
        for (c=getchar(); !isdigit(c); c=getchar())
            if (c=='-') flag=-1;
        for (x=c-48; c=getchar(), isdigit(c); )
            x=(x<<3)+(x<<1)+c-48; x*=flag;
    }
    
    struct Treap{
        //时刻牢记旋转操作不破坏bst的性质
        //小根堆  x:结点编号
        //空间复杂度:插入次数
        //v:结点的值  w:结点的优先级
        int tot, root, siz[maxn], v[maxn], w[maxn], s[maxn][2];
        void up(int x){ siz[x]=siz[s[x][0]]+siz[s[x][1]]+1; }
        void spin(int &x, int p){  //把x所指的p孩子旋转上来
            int t=s[x][p];
            s[x][p]=s[t][!p]; s[t][!p]=x;  //重构关系
            up(x); up(t); x=t;  //维护子树大小  将当前位置更换
        }
        void ins(int &x, int c){  //不停把优先级小的转上来
            if (!x){ x=++tot; siz[x]=1;
                v[x]=c; w[x]=randint(); return; }
            ++siz[x];
            if (c<=v[x]){ ins(s[x][0], c);  //左边是v小于等于v[x]的结点
                if (w[s[x][0]]<w[x]) spin(x, 0); }
            else { ins(s[x][1], c);
                if (w[s[x][1]]<w[x]) spin(x, 1); }
        }
        void del(int &x, int c){  //把这个数一直转到叶子节点然后删除
            if (v[x]==c){
                if (!s[x][0]||!s[x][1]){
                    x=s[x][0]+s[x][1]; return; }
                if (w[s[x][0]]>w[s[x][1]]){
                    spin(x, 1); del(s[x][0], c); }
                else{ spin(x, 0); del(s[x][1], c); }
            }  //别忘记这里也要update!
            else if (v[x]>c) del(s[x][0], c);
            else del(s[x][1], c);
            up(x);  //由于没有旋转操作需要手动维护
        }
        int rank(int x, int c){  //询问c的最小排名
            if (!x) return 1;
            if (c<=v[x]) return rank(s[x][0], c);
            else return rank(s[x][1], c)+siz[s[x][0]]+1;
        }
        int atrank(int x, int c){  //询问第c个数
            if (siz[s[x][0]]==c-1) return v[x];
            if (siz[s[x][0]]>=c) return atrank(s[x][0], c);
            else return atrank(s[x][1], c-siz[s[x][0]]-1);
        }
        int pre(int x, int c){  //询问小于c且最大的数
            if (!x) return -INF;
            if (v[x]<c) return max(v[x], pre(s[x][1], c));  //答案有可能是根
            else return pre(s[x][0], c);
        }
        int nxt(int x, int c){  //询问大于c且最小的数
            if (!x) return INF;
            if (v[x]>c) return min(v[x], nxt(s[x][0], c));  //答案有可能是根
            else return nxt(s[x][1], c);
        }
    }treap;
    
    int n, op, x;
    
    int main(){
        get(n); srand(time(NULL));
        for (int i=0; i<n; ++i){
            get(op); get(x);
            if (op==1) treap.ins(treap.root, x);
            if (op==2) treap.del(treap.root, x);
            if (op==3) printf("%d
    ", treap.rank(treap.root, x));
            if (op==4) printf("%d
    ", treap.atrank(treap.root, x));
            if (op==5) printf("%d
    ", treap.pre(treap.root, x));
            if (op==6) printf("%d
    ", treap.nxt(treap.root, x));
        }
        return 0;
    }
    
  • 相关阅读:
    关于产品的一些想法
    js中this的问题
    C# webkit 内核浏览器 访问https 网站 提示 Problem with the SSL CA cert (path? access rights?)
    SSL握手中win xp和SNI的那点事
    VMware安装GHOST版XP不成功的解决
    Inno Setup入门(十二)——Pascal脚本(1)
    VS打包软件部署------ClickOnce应用安装 (各版本.net引导文件安装,再发布文档离线安装下载地址)
    利用VS自带的命令行工具查看和生产PublicKeyToken
    获取批处理文件所在路径
    Nginx Windows详细安装部署教程
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/8621443.html
Copyright © 2011-2022 走看看