专栏文章

splay模板随手记

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mioymp6h
此快照首次捕获于
2025/12/03 03:17
3 个月前
此快照最后确认于
2025/12/03 03:17
3 个月前
查看原文

实现splay操作:

序言:

一:初始操作

1.初始化:
CPP
int rt,id;
//树根和总节点编号 
int f[N],ch[N][2],val[N];
//父亲,左右儿子,值 
int cnt[N],sz[N];
//副本数,子树大小 
2.判左右儿子:
右儿子为1.左儿子为0
CPP
inline bool dir(int x){
    return x==ch[f[x]][1];
}
3.单点更新子树大小:
注意:一个节点的子树大小表示其左子树大小,右子树大小和此节点副本数之和
CPP
inline void push_up(int x){
    sz[x]=cnt[x]+sz[ch[x][0]]+sz[ch[x][1]];
}
4.单旋操作(zig,zag融合):
zig,zag示意图
CPP
inline void rotate(int x){
	int y=f[x],z=f[y];//y为x父亲,z为x祖父 
	bool r=dir(x); 
	ch[y][r]=ch[x][!r];//y代表x的子树连接x的另一子树 
	ch[x][!r]=y;//x的另一子树更新为y 
	if (z) ch[z][dir(y)]=x;
	//如果x有祖父节点,让x取代原y位置 
	if (ch[y][r]) f[ch[y][r]]=y;
	//如果y原来代表x的子树位置现有子树,让子树认y做父亲
	//第四行已经更新儿子关系,未更新父亲关系 
	f[y]=x;f[x]=z;
	//让y反认父亲,让x认祖父当父亲(取代y节点位置) 
	push_up(y);//更新y子树关系 
	push_up(x);//更新x子树关系 
}
5.splay伸展操作(将x旋转到根):
  • 一步到根只需转x
    一步zig
  • >=2>=2步时判断x和y是否同侧:
    (1) x和y同侧:则需要zig-zig(先转y再转x)
    zig-zig
    (2) x和y异侧:则需要zig-zag(转两次x)
    zig-zag
CPP
inline void splay(int& z,int x){
	//z为根节点,x为上旋节点 
	int w=f[z];//设w为根节点z的父亲(当x的父亲为w时,x就是根了) 
	for (int y;(y=f[x])!=w;rotate(x))//y是x父亲 
		if (f[y]!=w)//当旋转操作还差>=2步到根时 
			rotate(dir(x)==dir(y)?y:x);
			//当x和y同为左/右子树启用zig-zig(转y 转x)
			//当x和y左右子树性质不同用zig-zag(转x 转x)
			//当旋转操作只差一步到根时只需旋转x到根 
	z=x;//把z(即rt)更新为x 
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...