洛谷 P3369 【模板】普通平衡树(Treap/SBT)
题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
-
插入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 原名:普通平衡树
在此鸣谢
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define MAXN 100001 using namespace std; int se,root,siz[MAXN],fa[MAXN],ch[MAXN][2],key[MAXN],cnt[MAXN]; void update(int x){ siz[x]=cnt[x]; if(ch[x][0]) siz[x]+=siz[ch[x][0]]; if(ch[x][1]) siz[x]+=siz[ch[x][1]]; } int getson(int x){ return ch[fa[x]][1]==x; } void rotate(int x){ int f=fa[x],ff=fa[f],k=getson(x); ch[f][k]=ch[x][k^1];fa[ch[f][k]]=f; ch[x][k^1]=f;fa[f]=x; fa[x]=ff; if(ff) ch[ff][ch[ff][1]==f]=x; update(f); update(x); } void splay(int x){ for(int f;f=fa[x];rotate(x)) if(fa[f]) rotate(getson(x)==getson(f)?f:x); root=x; } void create(int x){ se++; key[se]=x; siz[se]=cnt[se]=1; ch[se][1]=ch[se][0]=fa[se]=0; } void insert(int x){ if(!root){ create(x); root=se; } else{ int now=root,f=0; while(1){ if(key[now]==x){ cnt[now]++; siz[now]++; splay(now); break; } f=now; now=ch[f][x>key[f]]; if(!now){ create(x); fa[se]=f; ch[f][x>key[f]]=se; splay(se); break; } } } } int findpos(int x){ int now=root,ans=0; while(1){ if(x<key[now]) now=ch[now][0]; else{ ans+=siz[ch[now][0]]; if(x==key[now]){ splay(now); return ans+1; } ans+=cnt[now]; now=ch[now][1]; } } } int findx(int x){ int now=root; while(1){ if(ch[now][0]&&x<=siz[ch[now][0]]) now=ch[now][0]; else{ int tmp=(ch[now][0]?siz[ch[now][0]]:0)+cnt[now]; if(x<=tmp) return key[now]; x-=tmp; now=ch[now][1]; } } } int pre(){ int now=ch[root][0]; while(ch[now][1]) now=ch[now][1]; return now; } int net(){ int now=ch[root][1]; while(ch[now][0]) now=ch[now][0]; return now; } void clear(int x){ fa[x]=siz[x]=ch[x][0]=ch[x][1]=cnt[x]=key[x]=0; } void deletee(int x){ int t=findpos(x); if(cnt[root]>1){ cnt[root]--; siz[root]--; return ; } if(!ch[root][0]&&!ch[root][1]){ clear(root); root=0; return ; } if(!ch[root][1]){ int tmp=root; root=ch[root][0]; fa[root]=0; clear(tmp); return ; } if(!ch[root][0]){ int tmp=root; root=ch[root][1]; fa[root]=0; clear(tmp); return ; } int prel=pre(),tmp=root; splay(prel); ch[root][1]=ch[tmp][1]; fa[ch[tmp][1]]=root; clear(tmp); update(root); } int main(){ int n,opt,x; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%d",&opt,&x); if(opt==1) insert(x); if(opt==2) deletee(x); if(opt==3) cout<<findpos(x)<<endl; if(opt==4) cout<<findx(x)<<endl; if(opt==5){ insert(x); cout<<key[pre()]<<endl; deletee(x); } if(opt==6){ insert(x); cout<<key[net()]<<endl; deletee(x); } } }
细雨斜风作晓寒。淡烟疏柳媚晴滩。入淮清洛渐漫漫。
雪沫乳花浮午盏,蓼茸蒿笋试春盘。人间有味是清欢。