普通平衡树学习笔记之Splay算法 (2)

根据这个判断\(x>t[u].val\)依次找\(x\)的位置,最后\(Splay\)一下就好了:

void Find(int x){ int u=root;//从根开始 if(!u)return;//没有树就直接跳出 while(t[u].ch[x>t[u].val] && x!=t[u].val){//依次向下找到当前值的点 u=t[u].ch[x>t[u].val];//更新 } splay(u,0);//旋转 }

这个到最后把这个位置\(Splay\)到了根,所以答案就是当前\(Find\)之后根的左儿子的儿子数。

\(3\)、求前驱后继(这个操作求出来的是节点编号)

我们首先需要找到排名,也就是操作\(2\),然后\(Splay\)到根节点,如果值大于当前值且查找的是后继或者小于当前且找前驱就直接返回,否则就向子节点转移。找到转移后最接近当前值的点,也就是说,如果第一次不满足,假如找前驱就向左走一个,然后找到左儿子的右节点的最下边的点,也就是最接近这个查找的值的点。

int Fr_last(int x,int flag){//前驱flag为0,后继为1 Find(x);//找到位置 int u=root;//根开始 if((t[u].val>x&&flag) || (t[u].val<x && !flag)){//当前点满足就直接返回 return u; } u=t[u].ch[flag];//向目标点(左或右)转移 while(t[u].ch[flag^1])u=t[u].ch[flag^1];//找到转移后最接近当前值的点 return u;//返回 } \(4\)、查找排名为\(x\)的值

首先从根节点开始,如果一共都没有\(x\)个数,那么就直接返回\(0\),不然的话就分别记录一下当前点的左右节点,然后判断,如果当前点的子节点树加上当前点的值的数量小于查找的排名,直接减去然后走到右儿子,不然就走到左儿子就行了。

int Find_thval(int x){ int u=root;//根开始 if(t[u].son<x){//如果没有这么多,直接返回0 return 0; } while(666666){//一直循环 int y=t[u].ch[0];//记录左儿子 if(x>t[y].son+t[u].cnt){//排名大就减去,然后走到右节点 x-=t[y].son+t[u].cnt; u=t[u].ch[1]; } else{ if(x<=t[y].son){//否则走到左节点 u=y; } else return t[u].val;//如果排名比上边的小,且比左节点的值大,这就是满足的价值,直接返回 } } }

我的这个代码有一些等号的取舍不同,所以在查找的时候传递参数需要加上一。

\(5\)、删除

我们需要首先找出这个点的前驱和后继,然后旋转下去,要删除的就是后继的左儿子,假如这个点的数量大于\(1\),就直接数量减一就好了,然后翻转到根节点,如果小于等于\(1\),那么就把这个点变成\(0\),结束!

void Delete(int x){ int Front=Fr_last(x,0);//前驱 int Last=Fr_last(x,1);//后继 splay(Front,0);//旋转 splay(Last,Front); int del=t[Last].ch[0];//找到需要删除的点 if(t[del].cnt>1){//大于1直接减 t[del].cnt--; splay(del,0); } else{//否则直接删除 t[Last].ch[0]=0; } } 总结

以上就是\(Splay\)的一些实现和操作,以后博客还会进行修改和完善,这些只是暂时自学时的理解,如果有神犇能给蒟蒻一些指导那就更好了。
完结撒花\(qwqq\)
下边推荐一个板子题普通平衡树板子

板子题代码:

细节的注释上边都写过了,祝愿大家学习愉快\(qwq\)

#include<bits/stdc++.h> using namespace std; const int maxn = 5e5+10; const int Inf = 2147483647; struct Node{ int son,ch[2],fa,cnt,val; }t[maxn]; int n,tot,root; void pushup(int x){ t[x].son = t[t[x].ch[0]].son+t[t[x].ch[1]].son+t[x].cnt; } void rotate(int x){ int y=t[x].fa; int z=t[y].fa; int k=t[y].ch[1]==x; t[z].ch[t[z].ch[1]==y]=x; t[x].fa=z; t[y].ch[k]=t[x].ch[k^1]; t[t[x].ch[k^1]].fa=y; t[x].ch[k^1]=y; t[y].fa=x; pushup(y); pushup(x); } void splay(int x,int goal){ while(t[x].fa!=goal){ int y=t[x].fa; int z=t[y].fa; if(z!=goal){ (t[y].ch[0]==x)^(t[z].ch[0]==x)?rotate(x):rotate(y); } rotate(x); } if(goal == 0){ root = x; } } void Find(int x){ int u=root; if(!u)return; while(t[u].ch[x>t[u].val] && x!=t[u].val){ u=t[u].ch[x>t[u].val]; } splay(u,0); } void Add(int x){ int u=root,fa=0; while(u&&t[u].val!=x){ fa=u; u=t[u].ch[x>t[u].val]; } if(u){ t[u].cnt++; } else{ u=++tot; if(fa)t[fa].ch[x>t[fa].val]=u; t[tot].ch[1]=0; t[tot].ch[0]=0; t[tot].val=x; t[tot].fa=fa; t[tot].cnt=1; t[tot].son=1; } splay(u,0); } int Fr_last(int x,int flag){ Find(x); int u=root; if((t[u].val>x&&flag) || (t[u].val<x && !flag)){ return u; } u=t[u].ch[flag]; while(t[u].ch[flag^1])u=t[u].ch[flag^1]; return u; } void Delete(int x){ int Front=Fr_last(x,0); int Last=Fr_last(x,1); splay(Front,0); splay(Last,Front); int del=t[Last].ch[0]; if(t[del].cnt>1){ t[del].cnt--; splay(del,0); } else{ t[Last].ch[0]=0; } } int Find_thval(int x){ int u=root; if(t[u].son<x){ return 0; } while(666666){ int y=t[u].ch[0]; if(x>t[y].son+t[u].cnt){ x-=t[y].son+t[u].cnt; u=t[u].ch[1]; } else{ if(x<=t[y].son){ u=y; } else return t[u].val; } } } int main(){ int n; Add(Inf); Add(-Inf); scanf("%d",&n); while(n--){ int opt; scanf("%d",&opt); int x; if(opt == 1){ scanf("%d",&x); Add(x); } if(opt == 2){ scanf("%d",&x); Delete(x); } if(opt == 3){ scanf("%d",&x); Find(x); int ans = t[t[root].ch[0]].son; printf("%d\n",ans); } if(opt == 4){ int ans; scanf("%d",&x); ans = Find_thval(x+1); printf("%d\n",ans); } if(opt == 5){ scanf("%d",&x); int ans = Fr_last(x,0); printf("%d\n",t[ans].val); } if(opt == 6){ scanf("%d",&x); int ans = Fr_last(x,1); printf("%d\n",t[ans].val); } } return 0; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygysf.html