题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
-
插入x数
-
删除x数(若有多个相同的数,因只删除一个)
-
查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
-
查询排名为x的数
-
求x的前驱(前驱定义为小于x,且最大的数)
- 求x的后继(后继定义为大于x,且最小的数)
输入输出格式
输入格式:
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号( 1 \leq opt \leq 61≤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 \leq 100000n≤100000
2.每个数的数据范围: [-{10}^7, {10}^7][?107,107]
来源:Tyvj1728 原名:普通平衡树
在此鸣谢
今天上课听了一下讲的treap,然后就根据之前写splay的“经验”yy了一下写法(为什么我不找个模板hhh),再然后调错2h+.......
其他的和splay比较类似,就是每个节点多一个随机数权值,保证堆性质,这样每次插入就不用旋转到根了,
直接转到父亲的随机权值比它小就行了;
一开始被删除坑了,,,删除不仅要把点下沉到叶子,而且要把父亲到根路径上的所有点的size减去1。
#include<bits/stdc++.h> #define ll long long #define maxn 100005 using namespace std; int f[maxn],ch[maxn][2]; int num[maxn],val[maxn]; int tot=0,n,m,siz[maxn]; int opt,pos,root; inline int get(int x){ return ch[f[x]][1]==x; } inline void update(int x){ siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]]; } inline void rotate(int x){ int fa=f[x],ffa=f[fa],tp=get(x); ch[fa][tp]=ch[x][tp^1],f[ch[fa][tp]]=fa; ch[x][tp^1]=fa,f[fa]=x; f[x]=ffa; if(ffa) ch[ffa][ch[ffa][1]==fa]=x; if(root==fa) root=x; update(fa),update(x); } inline void up(int x){ while(f[x]&&val[x]<val[f[x]]) rotate(x); } inline void down(int x){ int u; while(ch[x][0]||ch[x][1]){ if(!ch[x][0]||!ch[x][1]) u=ch[x][0]+ch[x][1]; else if(val[ch[x][0]]<val[ch[x][1]]) u=ch[x][0]; else u=ch[x][1]; rotate(u); } } inline void ins(int x){ if(!root){ root=++tot,num[tot]=x; val[tot]=rand(),siz[tot]=1; return; } int now=root,fa; while(now){ fa=now,siz[now]++,now=ch[now][x>num[now]]; } num[++tot]=x,val[tot]=rand(),siz[tot]=1; f[tot]=fa,ch[fa][x>num[fa]]=tot,update(fa); up(tot); } inline int kth(int k){ int now=root; while(now){ if(k<=siz[ch[now][0]]) now=ch[now][0]; else{ k-=siz[ch[now][0]]+1; if(k<=0) return num[now]; now=ch[now][1]; } } return -1; } inline int rank(int x){ int now=root,an=0; while(now){ if(num[now]<x) an+=siz[ch[now][0]]+1,now=ch[now][1]; else now=ch[now][0]; } return an; } inline void dec_node(int x){ while(x) siz[x]--,x=f[x]; } inline void del(int x){ int now=root; while(now){ if(num[now]==x) break; now=ch[now][x>num[now]]; } if(!now) return; down(now); if(now==root) root=0; ch[f[now]][get(now)]=0,dec_node(f[now]),f[now]=0; } inline int pre(int x){ int now=root,mx=-1000000000; while(now){ if(num[now]<x) mx=max(mx,num[now]),now=ch[now][1]; else now=ch[now][0]; } return mx; } inline int nxt(int x){ int now=root,mn=1000000000; while(now){ if(num[now]>x) mn=min(mn,num[now]),now=ch[now][0]; else now=ch[now][1]; } return mn; } int main(){ srand(time(0)); scanf("%d",&n); while(n--){ scanf("%d%d",&opt,&pos); if(opt==1) ins(pos); else if(opt==2) del(pos); else if(opt==3) printf("%d\n",rank(pos)+1); else if(opt==4) printf("%d\n",kth(pos)); else if(opt==5) printf("%d\n",pre(pos)); else printf("%d\n",nxt(pos)); } return 0; }