【学习笔记】平衡树
bst 容易被卡,是因为很容易构造数据把它卡成一棵不平衡的树使得查询变慢,所以所有平衡树的主要目的都是为了尽量维护 bst 的平衡性。
替罪羊树
个人认为比较暴力的平衡树,但是跑出来的效果很好,板子题总共比 FHQ-Treap,Splay 都快了 4s 左右。
维护
很简单,如果有一棵子树不平衡了,就重构这棵子树。
如何重构?一棵树重构时按照中序遍历时中间的端点当根节点的建法是可以建出一棵平衡二叉树。所以重构时把子树按中序遍历拍平保证性质,然后从中间分开重构即可做到
如何判断一棵子树是否平衡?替罪羊的精髓在于不需要严格不平衡,定义一个比例系数
Splay
注意到 Splay 除了值域查询从始至终跟值域都没有关系,这让我们联想到它能够在序列和点集等处有期望较为优秀的表现。
基本思想是你访问哪个节点就把哪个节点当做根。这种看起来就抽象的算法算下来一次操作复杂度是 均摊
写起来的优点应该就是维护的东西比较少,只有
最主要的操作就是把一个点搞到根上去。保证时间复杂度最重要的一步就是不管是什么函数只要有寻找一个节点的行为就要把那个节点旋到根上去,以及在修改结构的时候记得把要维护的东西先维护好。
先把最基本的单次旋转想好。
以左为例,右儿子是一样的。想象一下就是把右儿子断开连到父亲上面,然后父亲成为自己的右儿子,自己再取代父亲的位置。理解起来比较动态化,好玩! 但是代码实现起来比较难受。
然后还有一个函数叫 splay(p,to)
,也就是把
Splay 的很多函数都挺有意思的。比如多了个 pick(x)
,用处是把值最接近
用 Splay 维护区间操作(区间翻转)
让伟大的线段树望尘莫及。
处理
在序列操作上我们没有必要继续维护 bst 的性质,更加偏向于当做一种线段树使用。比如说在区间翻转里面直接把子树交换就好了。只要你的结构还是 bst 的结构 splay 的复杂度就不会出锅。
好吧我还是肤浅了,FHQ 也可以做到维护序列,只要按子树大小分裂一样可以很简单地打上 tag,甚至因为可持久化在维护序列的过程中要优于 splay。
无旋 Treap(FHQ-Treap)
码量相对最小,但是细节不少,容易敲错,记得背住。需要多维护一个
FHQ-Treap 的精髓在于分裂合并操作。
分裂操作将一棵 FHQ-Treap 按照
其他的很多操作有了分裂合并都变得简单。插入操作可以先新建一个节点,然后把 FHQ-Treap 按照值分裂,然后按照顺序合并回来。删除操作把 FHQ-Treap 分成小于等于大于三棵,把等于那棵的根的左右儿子合并就相当于抹掉了一个权值等于要删去的数的节点。然后按照顺序合并回来就好。查排名的的时候也可以分裂之后查小于那边的树的大小就直接是答案了。注意分裂完之后的合并。
挺好写的,如果不担心被卡一般是选择用 FHQ-Treap 的。
可持久化 Treap
注意到 splay 的复杂度是均摊的,我们没有办法在合理的复杂度内支持可持久化。
但是 FHQ 不一样。由于随机化的优越性每次修改都可以控制在
硬要做其实也能支持 可持久化文艺平衡树,需要在可持久化的过程中注意翻转 tag,在 pushdown 的时候要新建节点,导致空间开销极大。不清楚其空间复杂度上限为多少。但是将平衡树用结构体存起来能够有效地节省空间。
在 题解区找到的一篇不需要打 tag 的看上去很牛的可持久化文艺平衡树做法,原理是维护正反两棵平衡树然后翻转的时候把两棵平衡树对应的位置交换。理论上看起来很简洁,因为没有那么多的打 tag 而且空间是比较确定的大概十倍常数的
喵喵喵发现很多情况下题目不会让你合并两个平衡树所以你的 merge 只是过程中的操作根本没必要新建节点,所以空间常数大概小了一点。
哦哦哦你可以直接判断总共节点 id 的数量大于某个阈值或者数组大小的时候直接推掉重构,感性分析重构次数不会太多,因为你每次加的也就几倍
有趣的 trick 是可持久化 treap 可以 自己合并自己。注意到这么合并会导致一堆父节点共用了同样的子节点,也就是导致这个 treap 视觉上连树都不是。但是注意到你的复杂度还是对的。因为你实际上把这些粘在一起的子节点视为了多个节点只是没开出来而已,你 split 的时候本身就会新开一个节点作原本的意义,对你的复杂度根本产生不了影响。其实根本原因应该是 fhq 不需要记录与祖先有关的信息导致一个点就算连了多个父亲对应上去多个父亲也会被视作不同的点。反正好强就是了。
然后你在区间复制的时候如果把随机值复制出去显然有神犇能够构造数据卡你复制完形成的树,因为这相当于是假随机。但是你每次新给一个随机值会导致堆的性质根本没有而且你要对复制出来的每一个点都新给一个随机值复杂度直接爆炸。
考虑你直接不要那个随机值了,每次在合并的时候随机把一个当根。注意这里的概率不是
有旋 Treap
咕咕咕。
lct
咕咕咕。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)