FHQ 入土教程
应 Vector_S 要求。
如果觉得文章中的马蜂过于毒瘤,可以翻到最后看格式化过的。
前置知识:堆,BST。
FHQ Treap 是什么?
一种依靠 split 和 merge 保持平衡的平衡树。
广泛应用于序列维护问题。
结构体定义
考虑每个点需要维护什么。
$FHQ$ 是二叉树,所以要维护左右孩子 $l,r$。
$FHQ∈Treap∈Cartesian\ Tree$,当然要维护二元组 $(v,k)$。
这里规定 $v$ 维护 BST 性质,$k$ 维护小根堆性质。
一般平衡树题要维护排名信息,所以要维护每个点的子树大小 $s$。
还要有一个 $maintain$ (或者叫 $pushup$)来更新点信息,
这里的信息比较简单,只需要更新 $s$ 即可。
struct T
{
T *l, *r;int v, k, s;
T(int _v) : l(0), r(0), v(_v), k(rand()), s(1) {}
void p() {s = 1;if(l) s += l -> s;if(r) s += r -> s;}
}*r; //根
Split(x,k,a,b)
分为两种:按权值分裂和按大小分裂。
按权值分裂
将 $x$ 分裂出 $v≤k$ 和 $v>k$ 的两棵子树 $a,b$。考虑递归实现:
- $x$ 为空树:
a = b = 0; - $x.v>k$:
b = x, Split(x->l, k, a, b->l), b->p();
如果 $x.v>k$,则 $v≤k$ 的子树在 $x$ 的左子树中。
于是在 $x$ 的左子树中分裂出 $v≤k$ 的子树给 $a$,剩下的部分给 $b$ 的左子树。
$b$ 的右子树即为没人要的 $x$ 的右子树。
- $x.v≤k$:
a = x, Split(x->r, k, a->r, b), a->p();
同理,如果 $x.v≤k$,则 $v≤k$ 的子树在 $x$ 的右子树中。
于是在 $x$ 的右子树中分裂出 $v≤k$ 的子树给 $a$ 的右子树,剩下的部分给 $b$。
$a$ 的左子树即为 $x$ 的左子树。
void S(T *x, int k, T *&a, T *&b)
{
if(!x) {a = b = 0;return;}
if(x->v > k) b = x, S(x->l, k, a, b->l), b->p();
else a = x, S(x->r, k, a->r, b), a->p();
}
按大小分裂
先咕着。
Merge(a,b)
合并 $a,b$ 两棵树,调用时须保证 $a$ 与 $b$ 在 $v$ 的中序遍历意义上连续。
这里规定 $a$ 的 $v$ 比 $b$ 的 $v$ 小。仍然考虑递归实现:
- $a$ 为空树返回 $b$,$b$ 为空树返回 $a$。
- $a.k<b.k$:将 $a$ 的右子树与 $b$ 合并。
- $a.k≥b.k$:将 $a$ 与 $b$ 的左子树合并。
这个比较好理解吧。
T *M(T *a, T *b)
{
if(!a) return b;if(!b) return a;
if(a->k < b->k) {a->r = M(a->r, b);a->p();return a;}
else {b->l = M(a, b->l);b->p();return b;}
}
插入 v
分裂出权值 $≤v$ 和权值 $>v$ 的子树 $a,b$,用 $v$ 新建节点 $t$。
之后将 $a,t,b$ 顺次合并即可。
void I(int v) {T *a, *b;S(r, v, a, b);r = M(a, M(new T(v), b));}
删除 v
先分裂出权值 $≤v$ 和权值 $>v$ 的子树 $a,c$,
再把 $a$ 分裂成权值 $<v$ 和权值 $=v$ 的子树 $a,b$。
之后删掉一个 $=v$ 的点,可以 $b=Merge(b.l,b.r)$。
最后把 $a,b,c$ 顺次合并即可。
void D(int v) {T *a, *b, *c;S(r, v, a, c);S(a, v - 1, a, b);r = M(a, M(b->l, M(b->r, c)));delete b;}
查 v 的排名
分裂出权值 $<v$ 的子树 $a$,答案即为 $a.s+1$。
注意用完要合并回去。
int R(int v) {T *a, *b;int s;S(r, v - 1, a, b);s = (a ? a->s : 0) + 1;r = M(a, b);return s;}
第 k 大,前驱,后继
和 BST 一样,不会影响性质。
int K(T *x, int v)
{
int z = x->l ? x->l->s : 0;if(v == z + 1) return x->v;
if(v <= z) return K(x->l, v);else return K(x->r, v - z - 1);
}
int P(T *x, int v)
{
if(!x) return -1e9;
if(v <= x->v) return P(x->l, v);
else return max(x->v, P(x->r, v));
}
int N(T *x, int v)
{
if(!x) return 1e9;
if(v >= x->v) return N(x->r, v);
else return min(x->v, N(x->l, v));
}
完整代码
#include <cstdio>
#include <cstdlib>
int max(int a, int b) {return a > b ? a : b;}
int min(int a, int b) {return a < b ? a : b;}
struct T
{
T *l, *r;int v, k, s;
T(int _v) : l(0), r(0), v(_v), k(rand()), s(1) {}
void p() {s = 1;if(l) s += l -> s;if(r) s += r -> s;}
}*r;
void S(T *x, int k, T *&a, T *&b)
{
if(!x) {a = b = 0;return;}
if(x->v > k) b = x, S(x->l, k, a, b->l), b->p();
else a = x, S(x->r, k, a->r, b), a->p();
}
T *M(T *a, T *b)
{
if(!a) return b;if(!b) return a;
if(a->k < b->k) {a->r = M(a->r, b);a->p();return a;}
else {b->l = M(a, b->l);b->p();return b;}
}
void I(int v) {T *a, *b;S(r, v, a, b);r = M(a, M(new T(v), b));}
void D(int v) {T *a, *b, *c;S(r, v, a, c);S(a, v - 1, a, b);r = M(a, M(b->l, M(b->r, c)));delete b;}
int R(int v) {T *a, *b;int s;S(r, v - 1, a, b);s = (a ? a->s : 0) + 1;r = M(a, b);return s;}
int K(T *x, int v)
{
int z = x->l ? x->l->s : 0;if(v == z + 1) return x->v;
if(v <= z) return K(x->l, v);else return K(x->r, v - z - 1);
}
int P(T *x, int v)
{
if(!x) return -1e9;
if(v <= x->v) return P(x->l, v);
else return max(x->v, P(x->r, v));
}
int N(T *x, int v)
{
if(!x) return 1e9;
if(v >= x->v) return N(x->r, v);
else return min(x->v, N(x->l, v));
}
int main()
{
srand(388651);int n, o, v;scanf("%d", &n);
while(n--)
{
scanf("%d%d", &o, &v);
switch(o)
{
case 1: I(v);break;
case 2: D(v);break;
case 3: printf("%d\n", R(v));break;
case 4: printf("%d\n", K(r, v));break;
case 5: printf("%d\n", P(r, v));break;
case 6: printf("%d\n", N(r, v));break;
}
}
return 0;
}
格式化的:
#include <cstdio>
#include <cstdlib>
int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }
struct T
{
T *l, *r;
int v, k, s;
T(int _v) : l(0), r(0), v(_v), k(rand()), s(1) {}
void p()
{
s = 1;
if (l)
s += l->s;
if (r)
s += r->s;
}
} * r;
void S(T *x, int k, T *&a, T *&b)
{
if (!x)
{
a = b = 0;
return;
}
if (x->v > k)
b = x, S(x->l, k, a, b->l), b->p();
else
a = x, S(x->r, k, a->r, b), a->p();
}
T *M(T *a, T *b)
{
if (!a)
return b;
if (!b)
return a;
if (a->k < b->k)
{
a->r = M(a->r, b);
a->p();
return a;
}
else
{
b->l = M(a, b->l);
b->p();
return b;
}
}
void I(int v)
{
T *a, *b;
S(r, v, a, b);
r = M(a, M(new T(v), b));
}
void D(int v)
{
T *a, *b, *c;
S(r, v, a, c);
S(a, v - 1, a, b);
r = M(a, M(b->l, M(b->r, c)));
delete b;
}
int R(int v)
{
T *a, *b;
int s;
S(r, v - 1, a, b);
s = (a ? a->s : 0) + 1;
r = M(a, b);
return s;
}
int K(T *x, int v)
{
int z = x->l ? x->l->s : 0;
if (v == z + 1)
return x->v;
if (v <= z)
return K(x->l, v);
else
return K(x->r, v - z - 1);
}
int P(T *x, int v)
{
if (!x)
return -1e9;
if (v <= x->v)
return P(x->l, v);
else
return max(x->v, P(x->r, v));
}
int N(T *x, int v)
{
if (!x)
return 1e9;
if (v >= x->v)
return N(x->r, v);
else
return min(x->v, N(x->l, v));
}
int main()
{
srand(388651);
int n, o, v;
scanf("%d", &n);
while (n--)
{
scanf("%d%d", &o, &v);
switch (o)
{
case 1:
I(v);
break;
case 2:
D(v);
break;
case 3:
printf("%d\n", R(v));
break;
case 4:
printf("%d\n", K(r, v));
break;
case 5:
printf("%d\n", P(r, v));
break;
case 6:
printf("%d\n", N(r, v));
break;
}
}
return 0;
}

浙公网安备 33010602011771号