【模板】普通平衡树

 

题目描述

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

  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\n",splay.rank(b));
        }
        if(a==4) {
            printf("%d\n",splay.atrank(b));
        }
        if(a==5) {
            printf("%d\n",splay.lower(b));
        }
        if(a==6) {
            printf("%d\n",splay.upper(b));
        }
    }
    return 0;
}

 

posted @ 2017-07-28 20:22  zzzzx  阅读(202)  评论(0编辑  收藏  举报