平衡树的几种姿势: AVL Red&Black_Tree 码量爆炸,不常用;SBT 出于各种原因,不常用。
常用:
Treap 旋转 基于旋转操作和随机数堆 但不支持区间操作。
非旋转 基于随机数堆和拆分合并操作 常数较大
时间复杂度:很难被卡,均摊O(logN)
#include<cstdio> #include<iostream> #include<cstdlib> #define MAXN 100005 using namespace std; int ch[MAXN][2],key[MAXN],r[MAXN],size[MAXN],cnt[MAXN],root,sz,n,m; inline void update(int x) { size[x]=size[ch[x][1]]+size[ch[x][0]]+cnt[x]; } inline void rotate(int &x) { int wh=r[ch[x][1]]>r[ch[x][0]],son=ch[x][wh]; ch[x][wh]=ch[son][wh^1]; ch[son][wh^1]=x; update(x); update(son); x=son; } void insert(int &now,int x) { if(!now) { now=++sz; cnt[sz]=size[sz]=1; key[sz]=x; r[sz]=(rand()%100+rand()); return; } if(key[now]==x) { cnt[now]++; size[now]++; return; } insert(ch[now][key[now]<x],x); if(r[now]<r[ch[now][key[now]<x]]) rotate(now); else update(now); } void del(int &now,int x) { if(key[now]==x) { if(cnt[now]>1) { cnt[now]--; size[now]--; return; } if(ch[now][1]*ch[now][0]==0) { now=ch[now][1]+ch[now][0]; return; } rotate(now); del(ch[now][key[ch[now][1]]==x],x); update(now); return; } del(ch[now][key[now]<x],x); update(now); } inline int kth(int x) { int now=root; while(1) { if(size[ch[now][0]]>=x) { now=ch[now][0]; continue; } int lon=cnt[now]+size[ch[now][0]]; if(lon>=x) return key[now]; x-=lon; now=ch[now][1]; } } inline int rank(int x) { int now=root,ans=0; while(1) { if(key[now]==x) return ans+1+size[ch[now][0]]; if(x<key[now]) { now=ch[now][0]; continue; } ans+=cnt[now]+size[ch[now][0]]; now=ch[now][1]; } } inline int pre(int x) { int now=root,ans=-0x7fffffff; while(now) if(key[now]<x) { if(key[now]>ans) ans=key[now]; now=ch[now][1]; } else now=ch[now][0]; return ans; } inline int next(int x) { int now=root,ans=0x7fffffff; while(now) if(key[now]>x) { if(key[now]<ans) ans=key[now]; now=ch[now][0]; } else now=ch[now][1]; return ans; } int main() { freopen("phs.in","r",stdin); freopen("phs.out","w",stdout); scanf("%d",&n); while(n--) { int x,y; scanf("%d%d",&y,&x); switch(y) { case 1:insert(root,x);break; case 2:del(root,x);break; case 3:printf("%d\n",rank(x));break; case 4:printf("%d\n",kth(x));break; case 5:printf("%d\n",pre(x));break; case 6:printf("%d\n",next(x));break; } } return 0; }