• 【模板】普通平衡树


    题目描述

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

    1. 插入x数

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

    3. 查询x数的排名(若有多个相同的数,因输出最小的排名)

    4. 查询排名为x的数

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

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

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1:
    10
    1 106465
    4 1
    1 317721
    1 460929
    1 644985
    1 84185
    1 89851
    6 81968
    1 492737
    5 493598
    输出样例#1:
    106465
    84185
    492737

    说明

    时空限制:1000ms,128M

    1.n的数据范围:n<=100000

    2.每个数的数据范围:[-1e7,1e7]

    来源:Tyvj1728 原名:普通平衡树

    用splay写的。。。。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn = 100004;
    const int INF = 0x7fffffff;
    struct Splay {
    #define root e[0].ch[1]
    
        struct node {
            int v,father;
            int ch[2];
            int sum;
            int recy;
        } e[maxn];
        int n,points;//使用存储数,元素数
        Splay() {
            n=0;
            points=0;
        }
        void update(int x) {
            e[x].sum=e[e[x].ch[0]].sum+e[e[x].ch[1]].sum+e[x].recy;
        }
        int indentify(int x) {
            return e[e[x].father].ch[0]==x?0:1;
        }
    
        void connect(int x,int f,int son) {
            e[x].father=f;
            e[f].ch[son]=x;
        }
    
        void destroy(int x) {
            e[x].v=e[x].ch[0]=e[x].ch[1]=e[x].sum=e[x].recy=e[x].father=0;
            if(x==n)n--;
            return ;
        }
    
        int cerpoint(int v,int father) {
            e[++n].father=father;
            e[n].v=v;
            e[n].recy=e[n].sum=1;
            return n;
        }
        void rotate(int x) {
            int y=e[x].father;
            int mroot=e[y].father;
            int mrootson=indentify(y);
            int yson=indentify(x);
            int B=e[x].ch[yson^1];
            connect(B,y,yson);
            connect(y,x,(yson^1));
            connect(x,mroot,mrootson);
            update(y);
            update(x);
    
        }
        void splay(int at,int v) {
            v=e[v].father;
            while(e[at].father!=v) {
                int up=e[at].father;
                if(e[up].father==v)rotate(at);
                else if(indentify(up)==indentify(at)) {
                    rotate(up);
                    rotate(at);
                } else {
                    rotate(at);
                    rotate(at);
                }
            }
        }
        int find(int v) {
            int now=root;
            while(11101001) {
                if(e[now].v==v) {
                    splay(now,root);
                    return now;
                }
                int next=v<e[now].v?0:1;
                now=e[now].ch[next];
                if(!now)return 0;
            }
        }
        int build(int v) {
            points++;
            if(n==0) {
                root=1;
                cerpoint(v,0);
                return 0;
            }
            int now=root;
            while(11101001) { //向下找到一个空节点
                e[now].sum++;//自己的下级肯定增加了一个节点
                if(v==e[now].v) {
                    e[now].recy++;
                    return now;
                }
                int next = v<e[now].v?0:1;
                if(!e[now].ch[next]) {
                    cerpoint(v,now);
                    e[now].ch[next]=n;
                    return n;
                }
                now=e[now].ch[next];
            }
            return 0;
        }
        void insert(int x) { //插入元素时,先添加节点,再进行伸展
            int cc=build(x);
            splay(cc,root);
        }
        void pop(int v) {
            int dd=find(v);
            if(!dd)return ;
            points--;
            if(e[dd].recy>1) {
                e[dd].recy--;
                e[dd].sum--;
                return;
            }
            if(!e[dd].ch[0]) {
                root=e[dd].ch[1];
                e[root].father=0;
            } else {
                int l=e[dd].ch[0];
                while(e[l].ch[1])l=e[l].ch[1];
                splay(l,e[dd].ch[0]);
                int r=e[dd].ch[1];
                connect(r,l,1);
                connect(l,0,1);
                update(l);
            }
            destroy(dd);
        }
        int rank(int v) { //获取值为v的元素在这棵树里是第几小
            int ans=0,now=root;
            while(11101001) {
                if(e[now].v==v)return ans+e[e[now].ch[0]].sum+1;
                if(now==0)return 0;
                if(v<e[now].v)now=e[now].ch[0];
                else {
                    ans+=e[e[now].ch[0]].sum+e[now].recy,
                         now=e[now].ch[1];
                }
            }
        }
        int atrank(int x) {
            if(x>points)return -INF;
            int now=root;
            while(11101001) {
                int min_used=e[now].sum-e[e[now].ch[1]].sum;
                if(x>e[e[now].ch[0]].sum&&x<=min_used)break;
                if(x<min_used)now=e[now].ch[0];
                else {
                    x=x-min_used;
                    now=e[now].ch[1];
                }
            }
            splay(now,root);
            return e[now].v;
        }
        int upper(int v) {
            int now=root;
            int ans=INF;
            while(now) {
                if(e[now].v>v&&e[now].v<ans)ans=e[now].v;
                if(v<e[now].v)now=e[now].ch[0];
                else now=e[now].ch[1];
            }
            return ans;
        }
        int lower(int v) {
            int now=root;
            int ans=-INF;
            while(now) {
                if(e[now].v<v&&e[now].v>ans)ans=e[now].v;
                if(v>e[now].v)now=e[now].ch[1];
                else now=e[now].ch[0];
            }
            return ans;
        }
    } splay;
    int main() {
        int n;
        scanf("%d",&n);
        int a,b;
        for(int i=1; i<=n; i++) {
            scanf("%d%d",&a,&b);
            if(a==1) {
                splay.insert(b);
            }
            if(a==2) {
                splay.pop(b);
            }
            if(a==3) {
                printf("%d
    ",splay.rank(b));
            }
            if(a==4) {
                printf("%d
    ",splay.atrank(b));
            }
            if(a==5) {
                printf("%d
    ",splay.lower(b));
            }
            if(a==6) {
                printf("%d
    ",splay.upper(b));
            }
        }
        return 0;
    }
  • 相关阅读:
    instancetype
    字典转模型
    类前缀
    当你学不进去的时候 不妨看看大脑是怎么想的
    当你学不进去的时候 不妨看看大脑是怎么想的
    你属于开源性格测试六大分类中的哪一类呢
    你属于开源性格测试六大分类中的哪一类呢
    程序员会被淘汰吗?
    程序员会被淘汰吗?
    Java基础学习总结(49)——Excel导入导出工具类
  • 原文地址:https://www.cnblogs.com/sssy/p/7252449.html
Copyright © 2020-2023  润新知