Sol
正常的二叉搜索树+暴力重构
lc,rc分别表示i的左右子树
对以p为根的子树重构当且仅当siz[lc]>siz[p]∗alpha
或者siz[rc]>siz[p]∗alpha
alpha(∈[0.5,1]) 是自己设定的一个参数,规定了这棵树的平衡程度
当 alpha==0.5 时,几乎每次都要重构,树为平衡树,但是重构次数太多
当 alpha==1.0 时,不会重构,此时是普通的二叉搜索树,有可能卡成链重构方法:先对以p为根的子树DFS(中序遍历),将序号存在一个数组里。因为是中序遍历,因此数组内点的值是有序的,可以直接build
#define lc ch[p][0]
#define rc ch[p][1]
void build(int &p,int L,int R){
if(L>R){
p=0; //非常重要,将叶节点的信息清空,否则会形成图
return;
}
int mid=(L+R)>>1;
p=loc[mid];
build(lc,L,mid-1);
build(rc,mid+1,R);
if(lc) fa[lc]=p;
if(rc) fa[rc]=p;
pushup(p);
}
void DFS(int p){
if(lc) DFS(lc);
loc[++sum]=p;
if(rc) DFS(rc);
//lc=rc=0;//也可以在这里清空节点信息
}
Code
// by spli
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define lc ch[p][0]
#define rc ch[p][1]
using namespace std;
const int N=100010;
const int inf=0x3f3f3f3f;
const double alpha=0.75;
int n,m;
int rt=1,tot=1;
int loc[N],sum;
int ch[N][2],fa[N];
double siz[N];
int val[N];
inline void pushup(int p){
siz[p]=siz[lc]+siz[rc]+1;
}
inline bool banlc(int p){
if(siz[lc]>siz[p]*alpha) return 0;
if(siz[rc]>siz[p]*alpha) return 0;
return 1;
}
void build(int &p,int L,int R){
if(L>R){
p=0;
return;
}
int mid=(L+R)>>1;
p=loc[mid];
build(lc,L,mid-1);
build(rc,mid+1,R);
if(lc) fa[lc]=p;
if(rc) fa[rc]=p;
pushup(p);
}
void DFS(int p){
if(!p) return;
if(lc) DFS(lc);
loc[++sum]=p;
if(rc) DFS(rc);
}
void rebuild(int p){
sum=0;
DFS(p);
int f0=fa[p];
bool b=(ch[f0][0]!=p);
int cur;
build(cur,1,sum);
fa[cur]=f0;
ch[f0][b]=cur;
if(p==rt) rt=cur;
}
void ins(int v){
int p=rt,cur=++tot;
siz[cur]=1;
val[cur]=v;
bool b;
while(1){
siz[p]++;
b=(v>=val[p]);
if(ch[p][b]) p=ch[p][b];
else{
ch[p][b]=cur;
fa[cur]=p;
break;
}
}
int pos=0;
for(int i=cur;i;i=fa[i]){
if(!banlc(i)) pos=i;
}
if(pos) rebuild(pos);
}
inline int getpos(int p,int v){
while(1){
if(val[p]==v) return p;
if(v>val[p]) p=rc;
else p=lc;
}
}
inline void del(int v){
int p=getpos(rt,v);
if(lc&&rc){
int cur=lc;
while(ch[cur][1]) cur=ch[cur][1];
val[p]=val[cur];
p=cur;
}
int son=lc?lc:rc;
int f0=fa[p];
bool b=ch[f0][0]!=p;
ch[f0][b]=son;
fa[son]=f0;
for(int i=fa[p];i;i=fa[i]) siz[i]--;
if(p==rt) rt=son;
}
inline int getrank(int p,int v){
int ret=0;
while(p){
if(v>val[p]) ret+=siz[lc]+1,p=rc;
else p=lc;
}
return ret;
}
inline int kth(int p,int k){
while(1){
if(k<=siz[lc]) p=lc;
else if(k==siz[lc]+1) return p;
else k-=siz[lc],k--,p=rc;
}
}
inline int getpre(int p,int v){
int ret=-inf;
while(p){
if(v>val[p]) ret=max(ret,val[p]),p=rc;
else p=lc;
}
return ret;
}
inline int getsuc(int p,int v){
int ret=inf;
while(p){
if(v<val[p]) ret=min(ret,val[p]),p=lc;
else p=rc;
}
return ret;
}
int main(){
scanf("%d",&n);
siz[rt]=1;
val[rt]=-inf;
int op,x;
while(n--){
scanf("%d%d",&op,&x);
if(op==1) ins(x);
if(op==2) del(x);
if(op==3) printf("%d\n",getrank(rt,x));
if(op==4) printf("%d\n",val[kth(rt,x+1)]);
if(op==5) printf("%d\n",getpre(rt,x));
if(op==6) printf("%d\n",getsuc(rt,x));
}
return 0;
}