FHQ/无旋平衡树

这个平衡树似乎是对新手最友好的平衡树(至少比Splay友好)但似乎又不友好
众所周知,平衡树是一个可以高效进行查找操作的二叉树。一个以值域为关键字的平衡树的节点左边子树的值肯定都比这个点小,右边子树的值肯定都比这个点大。平衡树可以实现插入、删除、查找排名、前驱、后继等等功能。而 FHQ Treap 则只用到分裂和合并两个操作。
(图为一棵普通的平衡树)
分裂
基本函数:void split(int x, int bas, int &l, int &r)
。这个函数执行把以
函数代码:
1 | void split(int x, int bas, int &L, int &R){ |
(图为分裂一棵树的可视化)
合并
个人觉得合并理解起来比分裂简单的很多。基本函数:int merge(int l, int r)
,合并以
函数代码:
1 | int merge(int L, int R){ |
(图为合并一棵树的可视化)
只要理解了这两个操作,其他的操作都是简单的。
其他操作:
- 插入值
:将树以值 分裂为两棵树,再将 插入左树,再把左树和右树合并。 - 删除值
:分两种情况: - 若有多个则只删除一个
,其他 保留:分裂出小于 ,等于 ,大于 这三棵平衡树,将等于 的这一棵的左子树和右子树合并,这样就消掉了他的根,大小刚刚好 ,再分别合并这三棵树。 - 若有多个
则全删除:分裂出小于 ,等于 ,大于 这三棵树,将小于 和大于 这两棵树合并。这样等于 的这一棵树(可能有多个元素)就被完全消掉了!
- 若有多个则只删除一个
- 求数
的排名(小于 的数的个数 ):这个要记录以每个节点为根的子树的大小。定义这个变量为 siz
。把他塞到每个节点的结构体里。每次更新的时候再更新一下当前节点的siz
大小:tr[x].siz = tr[tr[x].ls].siz + tr[tr[x].rs].siz + 1
。查找排名即分裂出小于等于(即小于 )和大于等于 的两棵树,然后排名就是小于 的那棵树的 。 - 求第
大数:看这个根的左子树的大小,记其为 。若 ,那就说明第 大数就是根,就返回根。若 ,说明第 大数在左子树里,指针指向左子树的根,继续求第 大数。若 ,说明第 大数在右子树里,指针指向右子树的根,因为这个右子树没有记这个左子树和这个根,并且根据平衡树的性质,右子树的每一个数一定比左子树的每一个数和根大。那么就查找右子树的排名第 的数即可。递归求即可。 - 求数
的前驱(第一个比 小的数):分裂为小于等于 (小于 )和大于等于 的两棵树,记小于等于 的树的大小为 ,那就找这棵树的第 大数即可。 - 求数
的后继(第一个比 大的数):分裂为小于等于 的和大于 的两棵树,求大于 的这棵树的第 大(排名为 )数即可。
例题:P3369【模板】普通平衡树
操作即为上述操作。
1 |
|
P4008 文本编辑器
这个分裂就不是按照权值分裂,而是按照排名分裂。按照排名分裂的思路就相当于是把 分裂 操作 和 求第k大数 结合起来。这里的
Split 操作代码:
1 | void split(int x, int bas, int &l, int &r){ //这个是小于等于排名bas的分到左树,大于排名bas的分到右树 |
其他的都和上述操作一样。
这里的输出是根据排名用中序遍历输出,即“左根右”。这样就保证了我们输出的排名是单调递增的。
注意到使用 getchar
时不能开 ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
!
1 |
|
P3391 文艺平衡树
这道题要求我们支持旋转的操作。考虑旋转该如何在一棵二叉树上进行。
这里给出的解释是先交换根
把他搬到平衡树上,基本的 split
和 merge
就已经有这样的思想。那我们就只用记一个 lazytag
,每次扫到这里的时候更新一下即可。交换区间 lazytag
亦或上
基本代码(只需一个 pushdown
即可):
1 | void pushdown(int x){ |
其实发现这个 pushdown
和线段树里的是很像的。只要理解线段树这个应该不会太难。
把这个代码插到 split
函数和 merge
函数里。扫到这里的时候就 pushdown
更新一下。
(图为旋转一段区间(一棵树)的可视化)
1 |
|
P5055 可持久化文艺平衡树
要做到可持久化,我们借鉴之前学的可持久化线段树的思维,记录一个
Split 操作时每次修改要记得新建一个节点,因为这是基于之前的版本改的。而且新建节点时要复制之前节点的全部信息。否则你将会获得五彩斑斓的好成绩。
这里要记录一个区间和,那么就在结构体里新建一个 sum
变量即可,再在 pushup
函数里更新一下就做完了。
1 |
|
P3835 可持久化平衡树
这道题比上面那道题要简单,沿用上面那道题的可持久化思路就可以做了
1 |
|
- Title: FHQ/无旋平衡树
- Author: 11490DX
- Created at : 2024-10-31 18:25:58
- Updated at : 2025-02-18 07:24:23
- Link: https://11490dx.net/2024/10/31/fhqtreap-sum/
- License: This work is licensed under CC BY-NC-SA 4.0.