Splay
Splay是一种很好地维护一棵二叉搜索树的方法。
如果不知道什么是二叉搜索树,请看此页面。
基本函数
Splay的基本思想是,通过一系列的旋转操作,维持整棵二叉搜索树的平衡。
首先,我们假设我们需要维护的结构体是这个样子的:
解释:
s[2]
:左右子树。fa
:父亲。v
:节点权值。w
:节点大小。sz
:节点及其子树大小。
还有一些其他的东西就一一列举了,比如懒标记等等。
旋转
Splay之所以能够维持其平衡,依赖的就是这样的简单旋转操作。
左旋与右旋
对于这样一个图:

其中x节点有两个子树,A与B;x节点的父亲y节点还有一棵子树C;z节点是y节点的父亲。
我们将x节点旋转(这里x节点是其父亲y节点的左儿子,所以我们会将其右旋),结果是这个样子的:

当然,如果我们把x旋转回去的话,那就是左旋操作了。
总体来看是这个样子:

在进行旋转操作时,我们需要保持其中序遍历序列不变。
在刚刚的右旋操作中,我们来分析一下我们需要改变的边:

就是这三条标红的边。
那么对于这三条边,我们分别进行重构操作。
代码如下:
旋转完成之后,因为我们改变了树的结构,所以我们需要重新计算x和y的大小,有时候还有需要维护的其他信息。
注意这里需要先维护较低的y,再维护较高的x。
所以总的函数是这个样子的:
核心函数
我们在向splay中插入一个数之后,会强制将其旋转到根。
而在刚才的示例中,我们看到了,我们将x右旋之后,x就向上走了一点。
而经过不断的旋转,我们就可以让x节点走到根。
当然,我们也不是随便瞎转,因为旋转操作也是需要复杂度的。
而我们的最后目标是使之均摊之后达到尽量小的复杂度。
引用闫学灿的一句话:
“如果我们瞎转的话,就达不到的复杂度了。”
所以我们要根据x所处的位置来制定不同的旋转方案。
首先,我们对于x可能出现的几种情况分析一下:
-
x就是目标节点。
那么就不用转了。 -
x是目标节点的子节点。
那我们直接转一下x就可以了。
对于x的父亲也不是目标节点的情况,我们也分两种情况讨论。
-
x的父亲也不是目标节点,且x与其父亲的所在子树类型相同。
可以理解为x,x的父亲和x的父亲的父亲三个节点在一条直线上。
这样的话,我们就先旋转x的父节点,再旋转x。 -
x的父亲也不是目标节点,且x与其父亲的所在子树类型不同。
可以理解为x,x的父亲和x的父亲的父亲三个节点的连线是一条折线。
这样的话,我们旋转两次x。
这样不断判断,直到x到达目标节点。
同时我们需要注意,因为我们根节点是随着我们的不断旋转而不断变化的,所以我们需要即使更新根节点的信息。
代码如下:
其他操作
我们假设我们需要维护的是一棵可重序列的二叉搜索树。
插入
Splay的插入操作是比较复杂的。
假设我们需要向树中插入一个元素 ,那么我们分下列几种情况讨论:
- 如果树是空的,那就直接插入根节点。
- 如果当前节点的权值等于 ,那就增加当前节点的大小,并更新其与其父亲的信息。
- 否则就按照二叉搜索树的性质继续向下面的节点查找。
最后不要忘记将节点旋转到根。
删除
Splay不使用惰性删除,其删除操作也是比较复杂的。
假设我们想要删除节点 。
首先,我们将 旋转到根。
然后我们分类讨论:
- 如果 的大小不为1,那就减少其大小。
- 否则直接合并其两棵子树。
合并两棵树的操作很简单。如果我们假设需要合并的两棵树 和 中, 的最大值大于 的话,只需要将的 的最大值旋转到根,同时将 设置为其根节点的右子树即可。
查询k的排名
查询排名为k的数
查询k的前驱或后继
前驱定义为小于这个数的最大数,后继定义为大于这个数的最小数。
我们的思路是,先将其插入进去,这样它就会到根节点;然后查询其左子树内的最大值或右子树内的最小值即可。
例题
维护可重有序序列
洛谷板子题,要求我们支持维护一个有序序列,并支持上面讲的六种操作。
示例代码:Luogu P3369-splay
维护不可重序列,支持区间翻转
给个洛谷板子题的代码:
它这里面要求区间翻转,那么我们在进行每一次旋转操作时,我们首先将左边界的前驱旋转至根节点,接着再把右边界的后继旋转至根节点的下面,此时右边界的后继的左子树就是我们所要翻转的区间了。
我们顺便增加一个flag
标记,用来标记翻转次数。
示例代码:Luogu P3391
__EOF__

本文链接:https://www.cnblogs.com/kaiserwilheim/p/16005428.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现