fhq_treap学习笔记
P6136 【模板】普通平衡树(数据加强版)
是一棵treap,即以为关键词是一棵bst,以为关键词是一个堆。采用split()
与merge()
而非rotate()
维护,达到“非旋”的效果,使速度变快,码量变小,又称“非旋treap”。
定义
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)
:
以为关键字,将以为根的树分裂为两棵,一棵上面所有值都,另一棵上所有值都。较小一棵的根填充到上,较大一棵的根填充到上。
if(!k){return x=y=0,void();}
若,则当前已无树可以分裂,则上一层伸下来的寻求填充的地址与都应被填充为。
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);
抉择及的左/右子树应该被填充到哪里。若t[k].val<val
,则的左子树一定都,接下来只需分裂的右子树。因此,将的右子树分为两棵,一棵在(此时数值上已经等于了)的右子树上,一棵在仍然代填充的地址上。
若t[k].val>=val
同理。
PushUp(k);
原树已经不存在,此处之指的是已完成赋值的或。以为例。显然,相比原树现在许多子树的已发生了变化,因此需要更新。此处只更新是因为相比原树,右子树的一部分被拿走了;在本层没有发生变化。
注意:kkkk不能使用const int &来定义,因为地址传来传去会乱掉#
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;
}
根据进行合并。因为已知中的值全部都小于中的值,故可以如此不管其而合并。
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;
}
与一般的GetRank()
与GetVal()
一样。不使用常用而好写的split()
开再找,原因是循环比递归快。
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;
}
前驱:将裂到上,使之成为上最小的元素,上有着所有比小的元素。因此在上最大的元素即为的前驱。
后继同理。
完整代码:
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;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话