两个一起学的,就放一块了。
主要是用来存板子。
Splay
//This is a Splay Tree. #include <cstdio> #include <cstring> using namespace std; const int N=1e5+5,INF=0x3f3f3f3f; int n,root,cntnode; struct node //始终满足左小右大 { int fa,ch[2],val,siz,cnt; //int mark; //区间反转标记 }t[N]; inline bool get(int x) {return t[t[x].fa].ch[1]==x;} //右儿子?1:0 inline void upd(int x) {t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+t[x].cnt;} //更新计数 inline void zigzag(int x) //旋转操作 { int fa=t[x].fa; int gfa=t[fa].fa; int d1=get(x),d2=get(fa); t[fa].ch[d1]=t[x].ch[d1^1]; t[t[x].ch[d1^1]].fa=fa; //断开fa与x,连接fa与x的儿子 t[gfa].ch[d2]=x; t[x].fa=gfa; //断开gfa与fa,连接gfa与x t[fa].fa=x; t[x].ch[d1^1]=fa; //连接x与fa upd(fa); upd(x); //一定是先upd fa再upd x,因为此时fa是x的节点 } void splay(int x,int goal) //伸展操作,即将一个节点x不断旋转至goal的儿子的位置 { while(t[x].fa!=goal) { int fa=t[x].fa; int gfa=t[fa].fa; int d1=get(x),d2=get(fa); if(gfa!=goal) { if(d1==d2) zigzag(fa); //双旋操作——如果x与fa处在同一方向,要先旋转fa else zigzag(x); } zigzag(x); } if(goal==0) root=x; //这里用goal=0来实现把x变为根节点的操作 } //以上为维持splayTree功能的基本操作,以下将实现splay的几种常见用途 void insert(int val) //插入值功能 { int node=root,fa=0; while(node && t[node].val!=val) fa=node,node=t[node].ch[t[node].val<val]; //通过不断遍历树来找到插入位置 if(node) t[node].cnt++; //已有此编号 else { node=++cntnode; if(fa) t[fa].ch[t[fa].val<val]=node; t[node].fa=fa; t[node].val=val; t[node].cnt=t[node].siz=1; } splay(node,0); } int kth(int k) //第k小的数 { int node=root; for(;;) { int son=t[node].ch[0]; if(k<=t[son].siz) node=son; else if(k>t[son].siz+t[node].cnt) k-=t[son].siz+t[node].cnt, node=t[node].ch[1]; else return t[node].val; } } int find(int val) //查找值 { int node=root; while(t[node].val!=val && t[node].ch[t[node].val<val]) node=t[node].ch[t[node].val<val]; return node; } int getrk(int val) { splay(find(val),0); return t[t[root].ch[0]].siz; } int presuc(int val,int tp) //查找前驱后继,tp=0为前驱,tp=1为后继 { splay(find(val),0); int node=root; if(t[node].val<val&&!tp || t[node].val>val&&tp) //如果找到的节点满足要求就直接返回 return node; node=t[node].ch[tp]; while(t[node].ch[tp^1]) node=t[node].ch[tp^1]; //否则找节点左/右子树中最靠右/左的节点(根据平衡树的性质 return node; } void delet(int val) { int pre=presuc(val,0),suc=presuc(val,1); splay(pre,0); splay(suc,pre); //将pre旋转到根,suc旋转到pre的下面,那么suc的左子树就是要删除的 if(t[t[suc].ch[0]].cnt>1) { t[t[suc].ch[0]].cnt--; //常规的删除 splay(t[suc].ch[0],0); } else t[suc].ch[0]=0; } int main() { insert(-INF); insert(INF); scanf("%d",&n); for(int i=1,opt,x;i<=n;++i) { scanf("%d%d",&opt,&x); if(opt==1) insert(x); if(opt==2) delet(x); if(opt==3) printf("%d\n",getrk(x)); if(opt==4) printf("%d\n",kth(x+1)); if(opt==5) printf("%d\n",t[presuc(x,0)].val); if(opt==6) printf("%d\n",t[presuc(x,1)].val); } return 0; }
来源:https://www.cnblogs.com/wzzyr24/p/11965938.html