码迷,mamicode.com
首页 > 其他好文 > 详细

treap

时间:2018-03-22 10:51:41      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:const   参考   需要   spin   and   初始   旋转   数据结构   sdi   

treap

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

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

#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){  //把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 ask_id(int x, int c){  //询问c的最小排名
        if (!x) return 1;
        if (c<=v[x]) return ask_id(s[x][0], c);
        else return ask_id(s[x][1], c)+siz[s[x][0]]+1;
    }
    int ask_num(int x, int c){  //询问第c个数
        if (siz[s[x][0]]==c-1) return v[x];
        if (siz[s[x][0]]>=c) return ask_num(s[x][0], c);
        else return ask_num(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\n", treap.ask_id(treap.root, x));
        if (op==4) printf("%d\n", treap.ask_num(treap.root, x));
        if (op==5) printf("%d\n", treap.pre(treap.root, x));
        if (op==6) printf("%d\n", treap.nxt(treap.root, x));
    }
    return 0;
}

treap

标签:const   参考   需要   spin   and   初始   旋转   数据结构   sdi   

原文地址:https://www.cnblogs.com/MyNameIsPc/p/8621443.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!