splay 模板 洛谷3369

题目描述

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

插入 xx 数
删除 xx 数(若有多个相同的数,因只删除一个)
查询 xx 数的排名(排名定义为比当前数小的数的个数 +1+1 。若有多个相同的数,因输出最小的排名)
查询排名为 xx 的数
求 xx 的前驱(前驱定义为小于 xx ,且最大的数)
求 xx 的后继(后继定义为大于 xx ,且最小的数)
输入输出格式

输入格式:
第一行为 nn ,表示操作的个数,下面 nn 行每行有两个数 optopt 和 xx , optopt 表示操作的序号( 1 \leq opt \leq 6 1≤opt≤6 )

输出格式:
对于操作 3,4,5,63,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 \leq 100000 n≤100000

2.每个数的数据范围: [-{10}^7, {10}^7][−10
7
,10
7
]

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

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;
const int MAXN = 100005;
const int inf = 0x7f7f7f7f;

struct Node{
    int v,fa;
    int ch[2];
    int sum;
    int recy;
}node[MAXN];


int n,cnt,points;

inline void update(int x){
    node[x].sum=node[node[x].ch[1]].sum+node[node[x].ch[0]].sum+node[x].recy;   
}

inline bool jud(int x){
    return node[node[x].fa].ch[0]==x?0:1;
}

inline void connect(int x,int f,int son){
    node[x].fa=f;
    node[f].ch[son]=x;
}

inline void rotate(int x){
    int y=node[x].fa;
    int mroot=node[y].fa;
    int mrootson=jud(y);
    int yson=jud(x);
    int oth=node[x].ch[yson^1];
    connect(oth,y,yson);
    connect(y,x,(yson^1));
    connect(x,mroot,mrootson);
    update(y);update(x);
}

inline void splay(int at,int to){
    to=node[to].fa;
    while(node[at].fa!=to){
        int up=node[at].fa;
        if(node[up].fa==to) rotate(at);
        else if(jud(up)==jud(at)){
            rotate(up);
            rotate(at);
        }
        else{
            rotate(at);
            rotate(at);
        }
    }
}

inline int crepoint(int x,int f){
    node[++cnt].v=x;
    node[cnt].fa=f;
    node[cnt].sum=1;
    node[cnt].recy=1;
    return cnt;
}

inline void destroy(int x){
    node[x].v=node[x].fa=node[x].sum=node[x].recy=node[x].ch[0]=node[x].ch[1]=0;
    if(x==cnt) cnt--;
}

inline int find(int v){
    int now=node[0].ch[1];
    while(1){
        if(node[now].v==v){
            splay(now,node[0].ch[1]);
            return now;
        }
        int nxt=v<node[now].v?0:1;
        if(!node[now].ch[nxt]) return 0;
        now=node[now].ch[nxt];
    } 
}

inline int build(int x){
    points++;
    if(cnt==0){
        node[0].ch[1]=1;
        crepoint(x,0);
    }
    else{
        int now=node[0].ch[1];
        while(1){
            node[now].sum++;
            if(x==node[now].v){
                node[now].recy++;
                return now;
            }
            int nxt=x<node[now].v?0:1;
            if(!node[now].ch[nxt]){
                crepoint(x,now);
                node[now].ch[nxt]=cnt;
                return cnt;
            }
            now=node[now].ch[nxt];
        }
    }
    return 0;
}

inline void push(int x){
    int add=build(x);
    splay(add,node[0].ch[1]);
}

inline void pop(int v){
    int deal=find(v);
    if(!deal) return;
    points--;
    if(node[deal].recy>1){
        node[deal].recy--;
        node[deal].sum--;
        return;
    }
    if(!node[deal].ch[0]){
        node[0].ch[1]=node[deal].ch[1];
        node[node[0].ch[1]].fa=0;
    }
    else{
        int lef=node[deal].ch[0];
        while(node[lef].ch[1]) lef=node[lef].ch[1];
        splay(lef,node[deal].ch[0]);
        int rig=node[deal].ch[1];
        connect(rig,lef,1);connect(lef,0,1);
        update(lef); 
    }
    destroy(deal);
}

int rank(int x){
    int ans=0;
    int now=node[0].ch[1];
    while(1){
        if(node[now].v==x) return ans+node[node[now].ch[0]].sum+1;
        if(now==0) return 0;
        if(x<node[now].v) now=node[now].ch[0];
        else{
            ans+=node[node[now].ch[0]].sum+node[now].recy;
            now=node[now].ch[1];
        }
    }
    if(now) splay(now,node[0].ch[1]);
    return 0;
}

int atrank(int x){
    if(x>points)    return -inf;
    int now=node[0].ch[1];
    while(1){
        int minn=node[now].sum-node[node[now].ch[1]].sum;
        if(x>node[node[now].ch[0]].sum && x<=minn) break;
        if(x<minn) now=node[now].ch[0];
        else{
            x=x-minn;
            now=node[now].ch[1];
        }
    }
    splay(now,node[0].ch[1]);
    return node[now].v;
}

inline int lower(int x){
    int now=node[0].ch[1];
    int res=-inf;
    while(now){
        if(node[now].v<x && node[now].v>res) res=node[now].v;
        if(x>node[now].v) now=node[now].ch[1];
        else now=node[now].ch[0];
    }
    return res;
}

inline int upper(int x){
    int now=node[0].ch[1];
    int res=inf;
    while(now){
        if(node[now].v>x && node[now].v<res) res=node[now].v;
        if(x<node[now].v) now=node[now].ch[0];
        else now=node[now].ch[1];
    }
    return res;
}

int main(){
    scanf("%d",&n);
    push(inf);push(-inf);
    for(register int i=1;i<=n;i++){
        int opt,x;
        scanf("%d%d",&opt,&x);
        if(opt==1) push(x);
        else if(opt==2) pop(x);
        else if(opt==3) printf("%d\n",rank(x)-1);
        else if(opt==4) printf("%d\n",atrank(x+1));
        else if(opt==5) printf("%d\n",lower(x));
        else printf("%d\n",upper(x));
    }
    return 0;
}

转载于:https://www.cnblogs.com/sdfzsyq/p/9677117.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值