继续平衡树……
普通平衡树
描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
-
插入x数
-
删除x数(若有多个相同的数,因只删除一个)
-
查询x数的排名(若有多个相同的数,因输出最小的排名)
-
查询排名为x的数
-
求x的前驱(前驱定义为小于x,且最大的数)
-
求x的后继(后继定义为大于x,且最小的数)
输入
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
输出
对于操作3,4,5,6每行输出一个数,表示对应答案
样例输入
8
1 10
1 20
1 30
3 20
4 2
2 10
5 25
6 -1
样例输出
2
20
20
20
提示
n<=100000 所有数字均在-10^7到10^7内
分析
板子题,板子题,板子题
背模板,背模板,背模板
一开始用splay写,结果可能是因为第一次写吧,各种bugs,就放弃了。。。
听gsj大佬说treap版本的很好写,就去敲了个模板
在算后继的时候出了一点小差错,由于此题要求后继定义为大于x的最小值,所以不能取到等于x,那么在处理的时候就要注意大于等于的问题,然后就没什么要注意的了吧
代码
#include<bits/stdc++.h>
#define N 500000
#define in read()
#define inf (int)2e+9
using namespace std;
int n,ch[N][2],sze[N],rt=0,num[N],pri[N];
int a[N],tot=0;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return f==1?res:-res;
}
void pushup(int x) { sze[x]=sze[ch[x][0]]+sze[ch[x][1]]+num[x];}
//the first time I wrote function"pushup",I naively wrote "sze[x]+="
//how stupid I was!
void rotate(int &rt,int t){
int x=ch[rt][t];
ch[rt][t]=ch[x][t^1];
ch[x][t^1]=rt;
pushup(rt);pushup(x);//
rt=x;//you can not change the order
}
void insert(int &rt,int x){
if(rt){
if(a[rt]==x) num[rt]++;
else{
int t=x>a[rt];
insert(ch[rt][t],x);
if(pri[ch[rt][t]]<pri[rt]) rotate(rt,t);
}
}
else{
rt=++tot;sze[tot]=1;num[tot]=1;
a[tot]=x;pri[tot]=rand();
}
pushup(rt);//always remember to update
}
void del(int &rt,int x){
if(a[rt]==x){
if(num[rt]>1) num[rt]--;
else{
if(!ch[rt][0]&&!ch[rt][1]){
rt=0;
return;
}
else{
rotate(rt,pri[ch[rt][0]]<pri[ch[rt][1]]);
del(rt,x);
}
}
}
else del(ch[rt][x>a[rt]],x);
pushup(rt);
}
int findrank(int rt,int x){
if(!rt) return 0;
if(x>a[rt]) return sze[ch[rt][0]]+num[rt]+findrank(ch[rt][1],x);
return findrank(ch[rt][0],x);
}
int findkth(int rt,int x){//find the xth
if(x>sze[ch[rt][0]]&&x<=sze[ch[rt][0]]+num[rt]) return a[rt];
if(x<=sze[ch[rt][0]]) return findkth(ch[rt][0],x);
return findkth(ch[rt][1],x-sze[ch[rt][0]]-num[rt]);
}
int pre(int rt,int x){
if(!rt) return -inf;
if(x>a[rt]) return max(a[rt],pre(ch[rt][1],x));
return pre(ch[rt][0],x);
}
int suf(int rt,int x){
if(!rt) return inf;
if(x>=a[rt]) return suf(ch[rt][1],x);//just here,pay attetion to the mark"="
return min(a[rt],suf(ch[rt][0],x));
}
int main(){
n=in;
srand(time(0));
int opt,x;
while(n--){
opt=in;x=in;
if(opt==1) insert(rt,x);
if(opt==2) del(rt,x);
if(opt==3) printf("%d\n",findrank(rt,x)+1);
if(opt==4) printf("%d\n",findkth(rt,x));
if(opt==5) printf("%d\n",pre(rt,x));
if(opt==6) printf("%d\n",suf(rt,x));
}
return 0;
}
后续应该会补一下splay版本的,望监督