前记
把之前学的平衡树都写一下,最近更新:Splay
Treap
本人的Treap丢了,放之前学习的Treap看看
#include<bits/stdc++.h> using namespace std; struct Treap{ static const int MAXN=400000+10; static const int INF=2000000000; struct Node{ int val; int pri; int cnt; int r,l; int size; }tree[MAXN]; int root; int top; Treap(){ root=0; top=0; } void update(int node){ // 更新 node 的 size 值,相当于 Segment Tree 的 pushup tree[node].size=tree[tree[node].l].size+tree[tree[node].r].size+tree[node].cnt; } void zig(int& node) // 左旋,可以看到会修改 node 的值,因此传入了一个引用 { int root=tree[node].r; tree[node].r=tree[root].l; tree[root].l=node; update(node); update(root); node=root; } void zag(int& node) // 右旋 { int root=tree[node].l; tree[node].l=tree[root].r; tree[root].r=node; update(node); update(root); node=root; } void insert(int& node,int x) // 在 node 中插入 x { if(!node){ //新建结点 node=++top; //深度++,结点编号 tree[node].pri=rand(); //随机优先值 tree[node].val=x; //节点值 tree[node].size=0; //子数大小 tree[node].cnt=0; //计相同数的个数 tree[node].l=tree[node].r=0; //初始化左、右子数大小 } tree[node].size++; if(tree[node].val==x){ //发现相同结点 tree[node].cnt++; //相同结点数++ } else if(tree[node].val>x) //往左子树走 { insert(tree[node].l,x); if(tree[node].pri>tree[tree[node].l].pri) //按优先级旋转treap zag(node);//右旋 } else //往右子树走 { insert(tree[node].r,x); if(tree[node].pri>tree[tree[node].r].pri) //按优先级旋转treap zig(node);//左旋 } //update(node); //更新 } bool erase(int& node,int x) //删除 x { if(!node)//空就返回 return false; if(tree[node].val==x) //删除 { tree[node].size--; if(tree[node].cnt>1){ tree[node].cnt--; } else if(tree[node].l==0||tree[node].r==0){//更新结点 node=tree[node].l+tree[node].r; } else if(tree[tree[node].l].pri<tree[tree[node].r].pri) {//按优先级旋转treap zag(node); erase(node,x); //更新旋转后结点 } else { zig(node); erase(node,x); //更新旋转后结点 } return true; } else //往下找结点 { bool flag; if(tree[node].val>x){ flag=erase(tree[node].l,x); } else{ flag=erase(tree[node].r,x); } if(flag) tree[node].size--; return flag; } } int rank(int node,int x) //查询排名为xx的数, 有多少个数比x小,记得加1 { if(tree[node].val==x){ //找到返回左子树大小 ,左子数的所以结点必定小于根和右子树结点(BST性质 return tree[tree[node].l].size; } else if(tree[node].val<x){ //递归右子树找点,更新排名 return tree[tree[node].l].size+rank(tree[node].r,x)+tree[node].cnt; } else{ return rank(tree[node].l,x); //递归左子树找点,更新排名 } } int k_th(int node,int k) // 第 k 小数 { if(k<=tree[tree[node].l].size) return k_th(tree[node].l,k); k-=tree[tree[node].l].size+tree[node].cnt; if(k<=0) return tree[node].val; else return k_th(tree[node].r,k); } int pre(int x) // 前驱,即最接近 x 但又比它小的数 { int max1=-INF,node=root; while(node) { if(tree[node].val<x){ // 如果该结点值小于x,更新最大值,往右继续找(往大的找 max1=max(max1,tree[node].val); node=tree[node].r; } else // 否则往左找(往小的找 node=tree[node].l; } return max1; } int suf(int x) // 后继,代码很接近前驱 { int min1=INF,node=root; while(node){ if(tree[node].val>x){ // 如果该结点值大于x,更新最小值,往左继续找(往小的找 min1=min(min1,tree[node].val); node=tree[node].l; } else node=tree[node].r; // 否则往右找(往大的找 } return min1; } // 遍历整棵树,输出 // 输出格式为 “节点值(x节点个数)” void print(int node,int level){ if(!node) return; print(tree[node].l,level+1); cout<<tree[node].val<<" (x"<<tree[node].cnt<<"), "; print(tree[node].r,level+1); cout<<endl; } }T; int main(){ srand(time(0)); // 命令的含义应该能看懂吧 // 命令必须合法,没加不合法鲁棒 // 不合法命令可能会出现 Runtime Error 或者魔改 Treap // 命令的格式是:“命令 值” //cout<<"Commands list: del / ins / pre / suf / rnk / kth (Maybe error)"<<endl; int G; ios::sync_with_stdio(0); cin>>G; while(G--) { //cout<<"Print: "; //T.print(T.root,1); 遍历整棵树,输出 string m; int x; cin>>m>>x; if(m=="del"||m=="2") T.erase(T.root,x); else if(m=="ins"||m=="1") T.insert(T.root,x); else if(m=="pre"||m=="5") cout<<T.pre(x)<<endl; else if(m=="suf"||m=="6") cout<<T.suf(x)<<endl; else if(m=="rnk"||m=="3") cout<<T.rank(T.root,x)+1<<endl; else if(m=="kth"||m=="4") cout<<T.k_th(T.root,x)<<endl; } return 0; }
FHQ-Treap
//FHQtreap #include<bits/stdc++.h> #define maxn 1000001 using namespace std; int n,x,y,mode,cnt,root; struct kkk{ int size,val,pri,l,r; }tree[maxn]; //////////////////////////////////////////////////////////////////////////// int New(int val){ tree[++cnt].size=1; tree[cnt].val=val; tree[cnt].pri=rand(); tree[cnt].l=tree[cnt].r=0; return cnt; } void update(int node){ tree[node].size=tree[tree[node].l].size+tree[tree[node].r].size+1; } void spilt(int node,int &x,int &y,int val){ if(node==0){ x=y=0;return; } if(tree[node].val<=val){ x=node;spilt(tree[node].r,tree[x].r,y,val); }else{ y=node;spilt(tree[node].l,x,tree[y].l,val); } update(node); } int merge(int x,int y){ if(!x||!y)return x+y; if(tree[x].pri<tree[y].pri){ tree[x].r=merge(tree[x].r,y); update(x); return x; }else{ tree[y].l=merge(x,tree[y].l); update(y); return y; } } void find(int node,int val){ while(tree[tree[node].l].size+1!=val){ if(tree[tree[node].l].size>=val) node=tree[node].l; else val-=tree[tree[node].l].size+1,node=tree[node].r; } printf("%d\n",tree[node].val); } //////////////////////////////////////////////////////////////////////////// void insert(int val){ int x=0,y=0,z=0; z=New(val); spilt(root,x,y,val); x=merge(x,z); root=merge(x,y); } void del(int val){ int x=0,y=0,z=0; spilt(root,x,y,val); spilt(x,x,z,val-1); z=merge(tree[z].l,tree[z].r); x=merge(x,z); root=merge(x,y); } void rank(int val){ int x=0,y=0; spilt(root,x,y,val-1); printf("%d\n",tree[x].size+1); root=merge(x,y); } void pre(int val){ int x=0,y=0; spilt(root,x,y,val-1); find(x,tree[x].size); root=merge(x,y); } void suf(int val){ int x=0,y=0; spilt(root,x,y,val); find(y,1); root=merge(x,y); } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%d",&mode,&x); if(mode==1)insert(x); if(mode==2)del(x); if(mode==3)rank(x); if(mode==4)find(root,x); if(mode==5)pre(x); if(mode==6)suf(x); } }
FHQ-Treap 文艺平衡树
//FHQtreap #include<bits/stdc++.h> #define maxn 1000001 using namespace std; int n,m,x,y,mode,cnt,root,tag[maxn]; struct kkk{ int size,val,pri,l,r; }tree[maxn]; //////////////////////////////////////////////////////////////////////////// int New(int val){ tree[++cnt].size=1; tree[cnt].val=val; tree[cnt].pri=rand(); tree[cnt].l=tree[cnt].r=0; return cnt; } void pushdown(int x){ tag[x]^=1; swap(tree[x].l,tree[x].r); tag[tree[x].l]^=1;tag[tree[x].r]^=1; } void update(int node){ tree[node].size=tree[tree[node].l].size+tree[tree[node].r].size+1; } void spilt(int node,int &x,int &y,int val){ if(node==0){ x=y=0;return; } if(tag[node])pushdown(node); if(val>tree[tree[node].l].size){ x=node;spilt(tree[node].r,tree[node].r,y,val-tree[tree[node].l].size-1); }else{ y=node;spilt(tree[node].l,x,tree[node].l,val); } update(node); } int merge(int x,int y){ if(!x||!y)return x+y; if(tag[x])pushdown(x); if(tag[y])pushdown(y); if(tree[x].pri<tree[y].pri){ tree[x].r=merge(tree[x].r,y); update(x); return x; }else{ tree[y].l=merge(x,tree[y].l); update(y); return y; } } //////////////////////////////////////////////////////////////////////////// void insert(int val){ int x=0,y=0,z=0; z=New(val); spilt(root,x,y,val); x=merge(x,z); root=merge(x,y); } void rotate(int x,int y){ int a,b,c,d; spilt(root,a,b,y+1); spilt(a,c,d,x); tag[d]^=1; root=merge(merge(c,d),b); } void print(int x){ if(tag[x])pushdown(x); if(tree[x].l)print(tree[x].l); printf("%d ",tree[x].val); if(tree[x].r)print(tree[x].r); } int main(){ //srand(time(0)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)insert(i); //print(root);cout<<endl; for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); rotate(x-1,y-1); //cout<<endl;print(root);cout<<endl; } print(root); }
IST 文艺平衡树
#include<bits/stdc++.h> #define maxn 1000001 //不知道为什么我就是喜欢开怎么大,其实完全没必要 using namespace std; struct kkk{ int l,r,tag,x,size; }tree[maxn]; int t[maxn],Left[maxn],middle[maxn],Right[maxn],rub[maxn],tmp[maxn]; int n,m,x,y,tot,top,le,ri,mi,root; inline int read(){ //快读,形成好习惯 int s=0,w=1; char ch=getchar(); while(ch<='0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w; } int New(){ //新建节点 int pos=rub[tot--]; tree[pos].l=tree[pos].r=tree[pos].size=tree[pos].x=tree[pos].tag=0; return pos; } void pushdown(int node){ //pushdown if(tree[node].tag){ //如果有标记就操作 tree[node].tag=0; //原标记清0,和线段树一样 tree[tree[node].l].tag^=1; //左标记取相反值,就是0变成1,1变成0 swap(tree[tree[node].l].l,tree[tree[node].l].r); //交换左子树的左右孩子,因为要翻转嘛 tree[tree[node].r].tag^=1; //右标记取相反值 swap(tree[tree[node].r].l,tree[tree[node].r].r); //交换右子树的左右孩子 } } void pushup(int node){ //pushup tree[node].size=tree[tree[node].l].size+tree[tree[node].r].size; } void spilt(int node,int begin,int end,int x,int y){ //分裂 if(end<x){Left[++le]=node;return;} //如果查询区间在要修改区间左部,并入左数组 if(x<=begin&&end<=y){middle[++mi]=node;return;} //如果查询区间在要修改区间中,并入中数组 if(y<begin){Right[++ri]=node;return;} //如果查询区间在要修改区间右部,并入右数组 pushdown(node); //pushdown更新tag标记 int mid=begin+tree[tree[node].l].size-1; //注意,因为经过修改后的树不像线段树那么平衡,所以mid值有所变动 spilt(tree[node].l,begin,mid,x,y); //向左子树递归分裂 spilt(tree[node].r,mid+1,end,x,y); //向左子树递归分裂 rub[++tot]=node; //这里是垃圾回收 } void marge(){ //合并 int cnt=0; //记得数组清0,要按顺序合并哦 for(int i=1;i<=le;++i)t[++cnt]=Left[i]; //把左部分合并 for(int i=1;i<=mi;++i)t[++cnt]=middle[i]; //把中部分合并 for(int i=1;i<=ri;++i)t[++cnt]=Right[i]; //把右部分合并 while(cnt>1){ //重新建树过程 int mid=(cnt+1)/2; //取mid值 for(int i=1;i<=mid;++i){ //将线段树底部节点一一合并 int x=t[i*2-1],y=t[i*2]; if(!x||!y)t[i]=x+y; //如果有一个是空,特判 else{ int node=New(); //新建一个节点 tree[node].l=x;tree[node].r=y; //新节点指儿子 pushup(node); //pushup t[i]=node; //把新节点并入数组里 } } for(int i=mid+1;i<=cnt;++i)t[i]=0;//记得把剩下节点清0,原因是他们已经在上面合并过了,而且避免了奇偶的错误 cnt=(cnt+1)/2; //到下一层继续建树 }root=t[1]; //根更新 } void build(int node,int l,int r){ //建树 if(l==r){ tree[node].x=l; //初值是i嘛 tree[node].size=1; //树大小是1 return; }int mid=(l+r)>>1; //和线段树一毛一样 tree[node].l=++top; //新建左子树的编号 build(top,l,mid); //递归左子树建树 tree[node].r=++top; //新建右子树的编号 build(top,mid+1,r); //递归右子树建树 pushup(node); //pushup } void rotate(int x,int y){ //翻转 le=0,ri=0,mi=0; //记得左,中,右部分数组要清0 spilt(root,1,tree[root].size,x,y); //分裂 for(int i=1;i<=mi;++i)tmp[i]=middle[i]; //把中部分提取出来 for(int i=1;i<=mi;++i){ middle[i]=tmp[mi-i+1]; //翻过来,就是直接赋值嘛 tree[middle[i]].tag^=1; //打标记 swap(tree[middle[i]].l,tree[middle[i]].r); //交换左右子树 }marge(); //合并 } void print(int node){ //输出 pushdown(node); //pushdown if(tree[node].size==1){ printf("%d ",tree[node].x); //输出 return ; }print(tree[node].l);print(tree[node].r); //递归左右子树 } int main(){ n=read();m=read();root=top=1; //记得赋初值 build(1,1,n); //建树 for(int i=1;i<=m;++i){ x=read();y=read(); rotate(x,y); //翻转 }print(root); //输出 }
替罪羊树
思想:当平衡树不平衡时就重构
//替罪羊树 P3369 【模板】普通平衡树 #include<bits/stdc++.h> #define maxn 1000000 //数组大小 #define alpha 0.75 //替罪羊常数 #define L(x) tree[x].l //左儿子 #define R(x) tree[x].r //右儿子 #define F(x) tree[x].fa //父亲 using namespace std; struct Node{ int l,r,val,fa,size,sum,cnt; // l 表示 左儿子 , r 表示 右儿子 ,val 表示 值 , fa 表示 父亲 // size 表示 子树节点和 , cnt 表示 相同val的数量 , sum 表示 子树所有 cnt 的和 }tree[maxn],seq[maxn]; int n,len,tot,flag,root,rub[maxn],cnt,mode,x; int rublish(){ //垃圾回收,省空间 if(tot>0)return rub[tot--]; //如果垃圾数组有不用的编号就拿来用 return ++len; //没有就开一个新编号 } void New(int val,int node,int fa){ //新建节点 val 为值, node 是编号 , fa 表示 node 的父亲 tree[node].val=val;tree[node].fa=fa; tree[node].size=tree[node].cnt=tree[node].sum=1; tree[node].l=tree[node].r=0; } int Find(int x,int node){ //寻找 x 值 的编号 if(x<tree[node].val&&tree[node].l)return Find(x,tree[node].l); if(x>tree[node].val&&tree[node].r)return Find(x,tree[node].r); return node; } void update(int node,int x,int y){ //更新有修改信息的点 if(!node)return ; //如果跳过根了就结束 tree[node].size+=x; tree[node].sum+=y; if((double)tree[node].size*alpha<(double) //随便判要不要重构 max(tree[L(node)].size,tree[R(node)].size)) {flag=node;} //记录要重构的树根 update(tree[node].fa,x,y); }//重建树begin void dfs(int node){ //dfs把树拍扁成序列 if(node==0)return; dfs(L(node)); //先左 seq[++cnt]=tree[node]; //其实只需要记录部分信息,不过我太懒了 rub[++tot]=node; //扔进垃圾筒 dfs(R(node)); //后右 } int Rebuilding_Tree(int l,int r,int fa){ //把序列建为完全二叉树 if(l>r)return 0; //如果是空就返回 int mid=(l+r)>>1,node=rublish(); //取一个编号 tree[node].fa=fa;tree[node].cnt=seq[mid].cnt;tree[node].val=seq[mid].val; //基本信息赋值 tree[node].l=Rebuilding_Tree(l,mid-1,node);tree[node].r=Rebuilding_Tree(mid+1,r,node); //左右儿子重建 tree[node].sum=tree[L(node)].sum+tree[R(node)].sum+seq[mid].cnt;tree[node].size=r-l+1; //信息更新 return node; //返回根 } void rebuild(int node){ //重建树的主函数 cnt=0;dfs(node); if(node==root)root=Rebuilding_Tree(1,cnt,0); //如果根重构就特判 else{ if(L(F(node))==node)tree[F(node)].l=Rebuilding_Tree(1,cnt,F(node)); //如果原来是左儿子就放左边 else tree[F(node)].r=Rebuilding_Tree(1,cnt,F(node)); //不然就放右边 } }//重建树end void insert(int x){ //插入 if(root==0){root=rublish();New(x,root,0);return;} //根插入特判 int node=Find(x,root); //找到那个点 if(x==tree[node].val){ //如果之前就有就把数量加1 tree[node].cnt++; update(node,0,1); //更新 }else{ if(x<tree[node].val){ //没有就看是放左边还是右边 tree[node].l=rublish(); //取一个编号 New(x,tree[node].l,node); //新建节点 }else{ tree[node].r=rublish(); //取一个编号 New(x,tree[node].r,node); //新建节点 } update(node,1,1); //更新 } } void del(int x){ //删除 int node=Find(x,root);tree[node].cnt--; //直接找到节点然后数量减1 update(node,0,-1); //更新 } int Rank(int x){ //查询排名,和BST一样 int node=root,ans=0; while(tree[node].val!=x){ if(x<tree[node].val)node=tree[node].l; //往左找 else ans+=tree[L(node)].sum+tree[node].cnt,node=tree[node].r; //累加进答案往右找 if(node==0){break;} //找不到就退出 }ans+=tree[L(node)].sum; //加上左子树的数量 return ans+1; //加1 } int kth(int x){ //查询排名x的树,和BST一样 int node=root; while(1){ if(x<=tree[L(node)].sum)node=L(node); //往左找 else{ x-=tree[L(node)].sum; //减去左边的数量 if(x<=tree[node].cnt){ //如果在该节点中 return tree[node].val; //返回值 } x-=tree[node].cnt; //减去自己的值 node=R(node); //往右节点跑 }if(node==0)return 0; //找不到就返回 } } int pre(int x){ //查询前驱 int node=Rank(x);node--; //找到x的排名,减1就是前驱的排名 return kth(node); } int suf(int x){ //查询后继 int node=Rank(x);int y=Find(x,root); //找到x的排名,加上自己的数量就是后继的排名 if(tree[y].val==x)node+=tree[y].cnt; return kth(node); } int main(){ //主函数 scanf("%d",&n); for(int i=1;i<=n;i++){flag=-1; //重构flag赋初值 scanf("%d%d",&mode,&x); if(mode==1){insert(x);} if(mode==2){del(x);} if(mode==3){printf("%d\n",Rank(x));} if(mode==4){printf("%d\n",kth(x));} if(mode==5){printf("%d\n",pre(x));} if(mode==6){printf("%d\n",suf(x));} if(flag!=-1)rebuild(flag); } }
Splay
我tm终于学Splay啦
#include<bits/stdc++.h> #define inf 2147483647 #define maxn 1000001 #define L(node) tree[node].ch[0] //左儿子 #define R(node) tree[node].ch[1] //右儿子 #define F(node) tree[node].fa //父亲 #define compare(node,x) x>tree[node].val//比较x是node的左儿子还是右儿子 using namespace std; struct Node{ int ch[3],fa,cnt,sum,val; }tree[maxn]; int root,mode,x,len,n; int read(){ //快读 int f=0,o=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')o=-1;ch=getchar();} while(ch>='0'&&ch<='9'){f=f*10+ch-'0';ch=getchar();} return o*f; } void pushup(int node){ //pushup 更新数值个数 tree[node].sum=tree[L(node)].sum+tree[R(node)].sum+tree[node].cnt; } void New(int node,int x,int fa){ //新建节点 tree[node].ch[0]=tree[node].ch[1]=0; tree[node].fa=fa;tree[node].val=x; tree[node].cnt=tree[node].sum=1; } void ratate(int node){ int fa=tree[node].fa; //node节点的父亲 int gfa=tree[fa].fa; //node节点的爷爷 int z=compare(fa,tree[node].val); //判断 node是 fa 的左还是右孩子 tree[gfa].ch[compare(gfa,tree[fa].val)]=node; //将node变到爷爷的某个孩子上 tree[node].fa=gfa; //指认父亲 tree[fa].ch[z]=tree[node].ch[z^1]; //node原来在父亲的方向变为原node的反方向节点 tree[tree[node].ch[z^1]].fa=fa; //原node的反方向节点指认父亲 tree[node].ch[z^1]=fa; //node的反方向就是fa tree[fa].fa=node; //指认父亲 pushup(fa);pushup(node); //更新,因为fa在下面所以先更新fa } //1.node变到原来fa的位置 //2.fa变成了 node原来在fa的 相对的那个儿子 //3.fa的非node的儿子不变,node的 node原来在fa的 那个儿子不变 //4.node的 node原来在fa的 相对的 那个儿子 变成了 fa原来是node的那个儿子 void Splay(int node,int goal){ //把node旋转到goal上 while(tree[node].fa!=goal){ //父亲是目标就可以退出了 int fa=tree[node].fa; int gfa=tree[fa].fa; //cout<<node<<' '<<fa<<' '<<gfa<<endl; if(gfa!=goal){ //如果爷爷不是目标就不会执行双旋 (compare(fa,tree[node].val))!=(compare(gfa,tree[fa].val)) //如果fa和gfa和node不在一条链上 ?ratate(node) //将自己旋上去 :ratate(fa); //不然就先旋父亲 } ratate(node); //单旋 } if(!goal)root=node; } void Find(int x){ //查找x的位置,并把它Splay到根 int node=root;if(!node)return; while(x!=tree[node].val){ if(x<tree[node].val&&L(node))node=L(node);else if(x>tree[node].val&&R(node))node=R(node);else break; } Splay(node,0); //旋到根 } int Next(int x,int mode){ //查找x的 前驱 0/后继 1 Find(x);int node=root; if((tree[node].val>x&&mode==1)||(tree[node].val<x&&mode==0))return node; node=tree[node].ch[mode]; while(tree[node].ch[mode^1])node=tree[node].ch[mode^1]; return node; } void insert(int x){ //插入 int node=root,fa=0; while(tree[node].val!=x&&node){ fa=node; //记录父亲 node=tree[node].ch[compare(node,x)]; //向下找点 } if(node)tree[node].cnt++; //如果原来有该节点就累加数量 else{ node=++len; if(fa) tree[fa].ch[compare(fa,x)]=node; //父亲认儿子 New(node,x,fa); //新建节点 } Splay(node,0); //旋到根 } void del(int x){ //删除节点 int last=Next(x,0); //查前驱 int nxt =Next(x,1); //查后继 Splay(last,0);Splay(nxt,last); int node=tree[nxt].ch[0]; if(tree[node].cnt>1){ tree[node].cnt--; //减去个数 Splay(node,0); }else tree[nxt].ch[0]=0; //直接删除 } int kth(int x){ //查询排名x的树,和BST一样 int node=root; while(1){ if(x<=tree[L(node)].sum)node=L(node); //往左找 else{ x-=tree[L(node)].sum; //减去左边的数量 if(x<=tree[node].cnt)return tree[node].val; //如果在该节点中,就返回值 x-=tree[node].cnt; //减去自己的值 node=R(node); //往右节点跑 }if(node==0)return 0; //找不到就返回 } } int Rank(int x){Find(x); return tree[L(root)].sum;} //找Rank int pre(int x){return tree[Next(x,0)].val;} //前驱 int suf(int x){return tree[Next(x,1)].val;} //后继 int main(){ //主函数 insert(-inf);insert(inf); n=read(); for(int i=1;i<=n;i++){ mode=read();x=read(); if(mode==1)insert(x); if(mode==2)del(x); if(mode==3)printf("%d\n",Rank(x)); if(mode==4)printf("%d\n",kth(x+1)); if(mode==5)printf("%d\n",pre(x)); if(mode==6)printf("%d\n",suf(x)); } }
来源:https://www.cnblogs.com/hyfhaha/p/10678344.html