FHQ 入土教程

应 Vector_S 要求。

如果觉得文章中的马蜂过于毒瘤,可以翻到最后看格式化过的。

前置知识:堆,BST。

FHQ Treap 是什么?

一种依靠 split 和 merge 保持平衡的平衡树。

广泛应用于序列维护问题。

结构体定义

考虑每个点需要维护什么。

FHQ 是二叉树,所以要维护左右孩子 l,r

FHQTreapCartesian 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 分裂出 vkv>k 的两棵子树 a,b。考虑递归实现:

  1. x 为空树:a = b = 0;
  2. x.v>kb = x, Split(x->l, k, a, b->l), b->p();

如果 x.v>k,则 vk 的子树在 x 的左子树中。

于是在 x 的左子树中分裂出 vk 的子树给 a,剩下的部分给 b 的左子树。

b 的右子树即为没人要的 x 的右子树。

  1. x.vka = x, Split(x->r, k, a->r, b), a->p();

同理,如果 x.vk,则 vk 的子树在 x 的右子树中。

于是在 x 的右子树中分裂出 vk 的子树给 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 两棵树,调用时须保证 abv 的中序遍历意义上连续。

这里规定 avbv 小。仍然考虑递归实现:

  1. a 为空树返回 bb 为空树返回 a
  2. a.k<b.k:将 a 的右子树与 b 合并。
  3. a.kb.k:将 ab 的左子树合并。

这个比较好理解吧。

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;
}
posted @   Jijidawang  阅读(26)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示