treap模板

来源:互联网 发布:金蝶软件补丁 编辑:程序博客网 时间:2024/06/05 08:51

旋转版treap:

//1. 插入x数//2. 删除x数(若有多个相同的数,因只删除一个)//3. 查询x数的排名(若有多个相同的数,因输出最小的排名)//4. 查询排名为x的数//5. 求x的前驱(前驱定义为小于x,且最大的数)//6. 求x的后继(后继定义为大于x,且最小的数)const int N = 100000 + 10, INF = 2e9 + 10;struct node{    int val, pri, son[2];    int sz, num;    void init(int _val, int _pri, int _sz, int _num)    {        val = _val, pri = _pri, sz = _sz, num = _num;        son[0] = son[1] = 0;    }}tr[N];int tot, root;void init(){    tot = 0, root = 0;    tr[0].init(0, 0, 0, 0);}void update(int x){    tr[x].sz = tr[tr[x].son[0]].sz + tr[tr[x].son[1]].sz + tr[x].num;}void Rotate(int &x, int p)//p=0左旋,p=1右旋{    int y = tr[x].son[!p];    tr[x].son[!p] = tr[y].son[p];    tr[y].son[p] = x;    update(x); update(y);//必须先更新x后更新y    x = y;}void Insert(int &x, int val){    if(x == 0) tr[x = ++tot].init(val, rand(), 1, 1);    else    {        tr[x].sz++;        if(tr[x].val == val)        {            tr[x].num++;            return;        }        int p = val > tr[x].val;        Insert(tr[x].son[p], val);        if(tr[x].pri < tr[tr[x].son[p]].pri) Rotate(x, !p);    }}void del(int &x, int val){//删除之前可以先查看一下这个值是否存在    //if(x == 0) return;    if(tr[x].val == val)    {        if(tr[x].num > 1)        {            tr[x].sz--;            tr[x].num--;            return;        }        if(tr[x].son[0] && tr[x].son[1])        {            int p = tr[tr[x].son[0]].pri > tr[tr[x].son[1]].pri;            Rotate(x, p);            tr[x].sz--;//如果接下删除tr[x].son[p],注意处理tr[x].sz,因为这个一直TLE            del(tr[x].son[p], val);            //del(x, val); //注释掉的写法不用处理sz的问题,因为递归到下一层会处理        }        else        {            //x = tr[x].son[0] + tr[x].son[1];  //合并,很凝炼            if(tr[x].son[0] != 0) x = tr[x].son[0];            else x = tr[x].son[1];        }    }    else    {        int p = val > tr[x].val;        tr[x].sz--;        del(tr[x].son[p], val);    }}int get_kth(int x, int k){    //if(x == 0) return 0;    if(k > tr[tr[x].son[0]].sz + tr[x].num) return get_kth(tr[x].son[1], k - tr[tr[x].son[0]].sz - tr[x].num);    else if(k <= tr[tr[x].son[0]].sz) return get_kth(tr[x].son[0], k);    else return tr[x].val;}int get_rank(int x, int val){    //if(x == 0) return 0;    if(val == tr[x].val) return tr[tr[x].son[0]].sz + 1;    else if(val > tr[x].val) return get_rank(tr[x].son[1], val) + tr[tr[x].son[0]].sz + tr[x].num;    else return get_rank(tr[x].son[0], val);}//求前驱和后继用两种不同的方法,其实一种即可int get_prec(int x, int val){    int ans = -INF;    while(x)    {        if(val <= tr[x].val) x = tr[x].son[0];        else ans = max(ans, tr[x].val), x = tr[x].son[1];    }    return ans;}int get_succ(int x, int val){    if(! x) return INF;    if(val >= tr[x].val) return get_succ(tr[x].son[1], val);    else return min(tr[x].val, get_succ(tr[x].son[0], val));}int main(){    int n, op, val;    scanf("%d", &n);    init();    for(int i = 1; i <= n; i++)    {        scanf("%d%d", &op, &val);        if(op == 1) Insert(root, val);        else if(op == 2) del(root, val);        else if(op == 3) printf("%d\n", get_rank(root, val));        else if(op == 4) printf("%d\n", get_kth(root, val));        else if(op == 5) printf("%d\n", get_prec(root, val));        else if(op == 6) printf("%d\n", get_succ(root, val));    }    return 0;}

非旋转版treap

typedef pair<int, int> proot;const int N = 100000 + 10, INF = 2e9 + 10;struct node{    int l, r, val, pri, sz;    void init(int _val, int _pri, int _sz)    {        val = _val, pri = _pri, sz = _sz;        l = r = 0;    }}tr[N];int root, tot;void init(){    root = 0, tot = 0;    tr[0].init(0, 0, 0);}int new_node(int val){    tr[++tot].init(val, rand(), 1);    return tot;}void update(int x){    tr[x].sz = 1 + tr[tr[x].l].sz + tr[tr[x].r].sz;}proot split(int x, int k)//把树x分裂成两个树,前k个元素一个数,剩余的元素一个树{    if(! k) return proot(0, x);    proot y;    if(tr[tr[x].l].sz >= k)    {        y = split(tr[x].l, k);        tr[x].l = y.second;        update(x);        y.second = x;    }    else    {        y = split(tr[x].r, k - tr[tr[x].l].sz - 1);        tr[x].r = y.first;        update(x);        y.first = x;    }    return y;}int Merge(int x, int y)//把树x,y合并成一棵,并返回树根{    if(!x || !y) return x + y;    if(tr[x].pri < tr[y].pri)    {        tr[x].r = Merge(tr[x].r, y);        update(x);        return x;    }    else    {        tr[y].l = Merge(x, tr[y].l);        update(y);        return y;    }}bool Find(int x, int val){    if(!x) return false;    if(val == tr[x].val) return true;    else if(val < tr[x].val) return Find(tr[x].l, val);    else return Find(tr[x].r, val);}//int get_rank(int x, int val)//树中无重复值才能用这个//{//    if(!x) return 0;//    if(val == tr[x].val) return tr[tr[x].l].sz + 1;//    else if(val < tr[x].val) return get_rank(tr[x].l, val);//    else return tr[tr[x].l].sz + 1 + get_rank(tr[x].r, val);//}int get_rank(int x, int val)//排名为get_rank()+1{    if(!x) return 0;    return val <= tr[x].val ? get_rank(tr[x].l, val) : get_rank(tr[x].r, val) + tr[tr[x].l].sz + 1;}int get_kth(int x, int k){    if(tr[tr[x].l].sz + 1 == k) return tr[x].val;    else if(k <= tr[tr[x].l].sz) return get_kth(tr[x].l, k);    else return get_kth(tr[x].r, k - tr[tr[x].l].sz - 1);}void Insert(int val){//插入元素。首先确定新元素的排名,然后依据这个排名把树分裂成两个,然后把新元素夹在两个树中间,合并    int k = get_rank(root, val);    proot x = split(root, k);    int y = new_node(val);    root = Merge(Merge(x.first, y), x.second);}void del(int val){//删除元素。首先确定元素排名k,然后前k-1个分裂成一个树,剩余的元素再进行一次分裂,把第一个也就是待删除元素单独分裂出来,然后合并即可    int k = get_rank(root, val) + 1;    proot x = split(root, k-1);    proot y = split(x.second, 1);    root = Merge(x.first, y.second);}//int get_prec(int x, int val)//{//    int ans = -INF;//    while(x)//    {//        if(val <= tr[x].val) x = tr[x].l;//        else ans = max(ans, tr[x].val), x = tr[x].r;//    }//    return ans;//}//int get_succ(int x, int val)//{//    if(! x) return INF;//    if(val >= tr[x].val) return get_succ(tr[x].r, val);//    else return min(tr[x].val, get_succ(tr[x].l, val));//}int get_prec(int root, int val){    int k = get_rank(root, val);    proot x = split(root, k-1);    proot y = split(x.second, 1);    int ans = tr[y.first].val;    root = Merge(Merge(x.first, y.first), y.second);    return ans;}int get_succ(int root, int val){    int k = get_rank(root, val+1);    proot x = split(root, k);    proot y = split(x.second, 1);    int ans = tr[y.first].val;    root = Merge(Merge(x.first, y.first), y.second);    return ans;}int main(){    int n, op, val;    scanf("%d", &n);    init();    for(int i = 1; i <= n; i++)    {        scanf("%d%d", &op, &val);        if(op == 1) Insert(val);        else if(op == 2) del(val);        else if(op == 3) printf("%d\n", get_rank(root, val) + 1);        else if(op == 4) printf("%d\n", get_kth(root, val));        else if(op == 5) printf("%d\n", get_prec(root, val));        else if(op == 6) printf("%d\n", get_succ(root, val));    }    return 0;}
原创粉丝点击