TESTTESTtesttest

fhq_treap学习笔记

Seg_Tree·2022-09-14 22:09·9 次阅读

fhq_treap学习笔记

P6136 【模板】普通平衡树(数据加强版)
是一棵treap,即以val为关键词是一棵bst,以rnd为关键词是一个堆。采用split()merge()而非rotate()维护,达到“非旋”的效果,使速度变快,码量变小,又称“非旋treap”。


定义

Copy
struct Node{ int val,siz,rnd; int ls,rs; }t[N]; inline int NewNode(const int val){ t[++TotNode]={val,1,rand(),0,0};return TotNode; }

没啥好说的,与最基础的treap相同。


split(const int &val,int k,int &x,int &y)
val为关键字,将以k为根的树分裂为两棵,一棵上面所有值都<val,另一棵上所有值都>val。较小一棵的根填充到x上,较大一棵的根填充到y上。

Copy
if(!k){return x=y=0,void();}

k=0,则当前已无树可以分裂,则上一层伸下来的寻求填充的地址xy都应被填充为0

Copy
if(t[k].val<val) split(val,t[x=k].rs,t[k].rs,y); else split(val,t[y=k].ls,x,t[k].ls);

抉择kk的左/右子树应该被填充到哪里。若t[k].val<val,则k的左子树一定都<val,接下来只需分裂k的右子树。因此,将k的右子树分为两棵,一棵在x(此时数值上已经等于k了)的右子树上,一棵在仍然代填充的地址y上。
t[k].val>=val同理。

Copy
PushUp(k);

原树k已经不存在,此处之k指的是已完成赋值的xy。以x为例。显然,相比原树现在许多子树的siz已发生了变化,因此需要更新。此处只更新x是因为相比原树k,右子树的一部分被拿走了;y在本层没有发生变化。

注意:kkkkk不能使用const int &来定义,因为地址传来传去会乱掉#


int merge(const int &x,const int &y)
将树xy合并为一棵树,其根作为返回值。

Copy
if(!x || !y)return x|y;

x为空或y为空,则xy即为他们合并后的样子。

Copy
if(t[x].rnd<t[y].rnd){ t[x].rs=merge(t[x].rs,y); PushUp(x); return x; } else { t[y].ls=merge(x,t[y].ls); PushUp(y); return y; }

根据rnd进行合并。因为已知x中的值全部都小于y中的值,故可以如此不管其val而合并。


Copy
inline void insert(const int &val){ int x=0,y=0; split(val,root,x,y); root=merge(merge(x,NewNode(val)),y); }

裂开,将新结点与x合并,再将合并后的树与y合并,将最后合并出来的树根放在root上。

Copy
inline void delet(const int &val){ int x=0,y=0,z=0,tmp; split(val,root,x,z); split(val+1,z,z,y); root=merge(merge(x,merge(t[z].ls,t[z].rs)),y); }

val为关键字将树裂为所有值全部小于valx,与大于等于valy两部分。
val+1为关键字将y裂为所有值全部等于valz,与大于valy两部分。
z的左儿子与右二子合并,使其根节点迷失。合并之后的树与x合并,再与y合并。

Copy
inline int GetRank(const int &val){ int k=root,ret=1; while(k){ if(t[k].val<val) ret+=t[t[k].ls].siz+1,k=t[k].rs; else k=t[k].ls; } return ret; } inline int GetVal(int rak){ int k=root; while(1){ if(t[t[k].ls].siz+1==rak)return t[k].val; if(t[t[k].ls].siz>=rak)k=t[k].ls; else rak-=t[t[k].ls].siz+1,k=t[k].rs; } return -1; }

与一般的GetRank()GetVal()一样。不使用常用而好写的split()开再找,原因是循环比递归快。

Copy
inline int GetPre(const int &val){ int x=0,y=0; split(val,root,x,y); int k=x; while(t[k].rs)k=t[k].rs; int ret=t[k].val; root=merge(x,y); return ret; } inline int GetNext(const int &val){ int x=0,y=0; split(val+1,root,x,y); int k=y; while(t[k].ls)k=t[k].ls; int ret=t[k].val; root=merge(x,y); return ret; }

前驱:将val裂到y上,使之成为y上最小的元素,x上有着所有比val小的元素。因此在x上最大的元素即为val的前驱。
后继同理。


完整代码:

Copy
class FHQ_Treap{ private: struct Node{ int val,siz,rnd; int ls,rs; }t[N]; int TotNode,root; inline void PushUp(const int &k){t[k].siz=t[t[k].ls].siz+t[t[k].rs].siz+1;} inline int NewNode(const int val){t[++TotNode]={val,1,rand(),0,0};return TotNode;} void print(const int &k){ if(!k)return; cout<<"ls: "<<t[t[k].ls].val<<" rs: "<<t[t[k].rs].val<<" ## "<<k<<endl; cout<<"size= "<<t[k].siz<<" val= "<<t[k].val<<endl; print(t[k].ls); print(t[k].rs); } void split(const int &val,int k,int &x,int &y){ if(!k){return x=y=0,void();} else {if(t[k].val<val) split(val,t[x=k].rs,t[k].rs,y); else split(val,t[y=k].ls,x,t[k].ls); PushUp(k);} } int merge(const int &x,const int &y){ if(!x || !y) return x|y; if(t[x].rnd<t[y].rnd){ t[x].rs=merge(t[x].rs,y); PushUp(x); return x; } else { t[y].ls=merge(x,t[y].ls); PushUp(y); return y; } } public: inline void DeBug(){print(root);} inline void insert(const int &val){ int x=0,y=0; split(val,root,x,y); root=merge(merge(x,NewNode(val)),y); } inline void delet(const int &val){ int x=0,y=0,z=0,tmp; split(val,root,x,z); split(val+1,z,z,y); root=merge(merge(x,merge(t[z].ls,t[z].rs)),y); } inline int GetRank(const int &val){ int k=root,ret=1; while(k){ if(t[k].val<val) ret+=t[t[k].ls].siz+1,k=t[k].rs; else k=t[k].ls; } return ret; } inline int GetVal(int rak){ int k=root; while(1){ if(t[t[k].ls].siz+1==rak)return t[k].val; if(t[t[k].ls].siz>=rak)k=t[k].ls; else rak-=t[t[k].ls].siz+1,k=t[k].rs; } return -1; } inline int GetPre(const int &val){ int x=0,y=0; split(val,root,x,y); int k=x; while(t[k].rs)k=t[k].rs; int ret=t[k].val; root=merge(x,y); return ret; } inline int GetNext(const int &val){ int x=0,y=0; split(val+1,root,x,y); int k=y; while(t[k].ls)k=t[k].ls; int ret=t[k].val; root=merge(x,y); return ret; } }T;
posted @   Seg_Tree  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
https://pic.cnblogs.com/face/
点击右上角即可分享
微信分享提示
目录