【模板】普通平衡树(Treap/SBT)

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  1. 插入x数

  2. 删除x数(若有多个相同的数,因只删除一个)

  3. 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)

  4. 查询排名为x的数

  5. 求x的前驱(前驱定义为小于x,且最大的数)

  6. 求x的后继(后继定义为大于x,且最小的数)

输入输出格式

输入格式:

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号( 1 leq opt leq 61opt6 )

输出格式:

对于操作3,4,5,6每行输出一个数,表示对应答案

#include <bits/stdc++.h>

using namespace std;
const int maxn = 100000+5;
const int inf = 2000000008;
int root,tot;
struct Splay{
    int ch[maxn][2],fa[maxn],siz[maxn],key[maxn], same[maxn];

    void init(int t, int val = 0, int par = 0){
        ch[t][0] = ch[t][1] = 0; key[t] = val;same[t] = 1; fa[t] = par;
    }
    void up(int t){
        siz[t] = siz[ch[t][1]] + siz[ch[t][0]] + same[t];
    }
    void init(){
        init(0, 0, 0);
        tot = root = 0;
    }
    void rotate(int x, int d){
        int y = fa[x];
        ch[y][d^1] = ch[x][d];
        if(ch[x][d])fa[ch[x][d]] = y;
        fa[x] = fa[y];
        if(fa[y]){
            if(y == ch[fa[y]][0])ch[fa[y]][0] = x;
            else ch[fa[y]][1] = x;
        }
        ch[x][d] = y;fa[y] = x;
        up(y);    // father first
        up(x);            
    }
    void splay(int x, int targrt){

        while(fa[x] != targrt){
            int y = fa[x];
            if(x == ch[y][0]){
                if(targrt != fa[y] && y == ch[fa[y]][0])
                    rotate(y, 1);
                rotate(x, 1);
            }
            else {
                if(targrt != fa[y]&& y == ch[fa[y]][1])
                    rotate(y, 0);
                rotate(x, 0);
            }
        }
        if(!targrt)root = x;
    }
    void insert( int x,int t = root, int par = 0){
        if(!t){
            t = ++tot;
            init(t, x, par);
            ch[par][x > key[par]] = t;
            splay(t, 0);
        }
        else{
            if(x == key[t]){
            same[t]++;    
            up(t);   //! 
            }
            else if(x < key[t]){
                insert(x, ch[t][0], t);
                up(t);
            }
            else {
                insert(x, ch[t][1], t);
                up(t);
            }
        }
        
    }

    int rank(int x,int t = root){
        if(!t)return 0;
        if(x == key[t])return siz[ch[t][0]]+1;
        if(x < key[t])return rank(x, ch[t][0]);
        return siz[ch[t][0]]+same[t]+rank(x, ch[t][1]);
    }
    int query(int x, int t = root){
        if(!x)return t;        
        if(x > siz[ch[t][0]] + same[t])
            return query(x - same[t] - siz[ch[t][0]], ch[t][1]);
        if(x <= siz[ch[t][0]])return query(x, ch[t][0]);
        return t;   
        
    }
    void Query(int x){
        printf("%d
",key[query(x)]);
    }
    void erase(int x){
        int t = root;
        while(key[t] != x)t = ch[t][x > key[t]];        
        splay(t, 0);
        if(same[t]>1){         
            same[t]--;
            up(t); //!
            return;
        }
        same[t] = 0;
        int y = ch[t][1];
        bool b;
        if(!y)y = ch[root][0], b = 1;
        else b = 0;
        if(!y)root = 0,same[t] = 0;//有可能只有一个节点
        while(ch[y][b])y = ch[y][b];
        splay(y, root);
        ch[y][b] = ch[root][b];
        if(ch[root][b]) fa[ch[root][b]] = y;
        fa[y] = 0; root = y;
        up(y);  //!
    }

    int getpre(int x){
        int ret = -inf, t = root;
        while(t){
            if(key[t] < x)ret = max(ret, key[t]);
            t = ch[t][x > key[t]];
        }
        return ret;
    }
    int getscc(int x){
        int ret = inf, t = root;
        while(t){
            if(key[t] > x)
                ret = min(ret, key[t]);
            t = ch[t][x >=key[t]];
        }
        return ret;
    }
   void print(){
        for(int i = 1; i <= tot; i++)
            printf("%d %d %d
",i, ch[i][0], ch[i][1]);
   }
}Tr;
int main()
{
    int n;
    scanf("%d",&n);
    Tr.init();
    while(n--){
        int opt,x;
        scanf("%d%d",&opt,&x);
        switch(opt){
            case 1:Tr.insert(x);break;
            case 2:Tr.erase(x);break;
            case 3:printf("%d
",Tr.rank(x));break;
            case 4:Tr.Query(x);break;
            case 5:printf("%d
",Tr.getpre(x));break;
            case 6:printf("%d
",Tr.getscc(x));break;
        }
        //Tr.print();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/EdSheeran/p/8688547.html