FHQ-treap 即非旋Treap,是一种短小精悍,功能丰富的平衡树。
据说它的效率介于 Treap 和 Splay 之间(可能是我的FHQ常数比较小,跑得比我的Treap还快)。
它可以实现 Splay 可以实现的所有功能,包括平衡树的基本操作和区间翻转操作。
它的实现难度比 Splay 要简单很多,没有 Splay 那么多转来转去的操作,不会令人头晕,而且FHQ代码的对称性良好,易于调试。
有两种 FHQ-Treap,一种是按值为关键字的,一种是按下标为关键字的(适用于区间翻转等操作时)。
FHQ-Treap 类似于Treap,都有一个随机的 key 值,以此来保持树的平衡。
Split (分裂) & merge (合并)
FHQ-Treap 的核心操作为 split \text{split} split (分裂) 和 merge \text{merge} merge (合并)。
split ( r o o t , v a l , x , y ) \text{split}(root,val,x,y) split(root,val,x,y) 表示将 r o o t root root 的子树拆分为两半,一半中的值(或下标)都小于等于 v a l val val, 一半的值都大于 v a l val val。
merge ( x , y ) \text{merge}(x,y) merge(x,y) 表示将 x x x 子树和 y y y 子树合并起来,要保证x中的元素都小于y中的元素。
具体操作都是依靠 split \text{split} split 和 merge \text{merge} merge 来实现的。
// 按值为关键字
struct Node
{
int l,r; // 左右儿子编号
int val;// 真实值
int key;// 随机值
int size;// 子树大小
}fhq[N];
void pushup(int u){
// 维护其子树大小
fhq[u].size = fhq[fhq[u].l].size + fhq[fhq[u].r].size + 1;
}
inline void split(int u,int val,int &x,int &y) // 递归实现
{
if(!u) {
// 空节点
x = y = 0;
return;
}
if(fhq[u].val <= val) {
// 点的值大于val,递归其右儿子
x = u;
split(fhq[u].r,val