FHQ Treap模版

在保持平衡树前提下通过随机数尽量减少树的高度log(n) ;

主要操作:将树劈成左右树,对两颗树进行合并

cpp 复制代码
// 定义 FHQ Treap 的节点结构
struct Node {
    int l, r;       // l: 左子树下标, r: 右子树下标
    int id;         // id: 记录这个节点对应原本的哪个起点 s
    long long val;  // val: 当前累积的宝藏总和 (必须用 long long,因为会爆 int)
    long long lazy; // lazy: 区间加法的懒标记
    unsigned int rnd; // rnd: 随机优先级,维持树的平衡
} tr[*N*];

int root;       // 根节点编号
int idx;        // 内存池计数器,当前用到了第几个节点
long long ans[*N*]; // 存储最终每个起点的答案

// 生成随机数,用于维持 Treap 平衡
mt19937 rng(chrono::steady_clock::*now*().time_since_epoch().count());

// 创建新节点
// v: 初始宝藏值, id: 起点编号
int new_node(long long v, int id) {
    idx++;
    tr[idx].l = tr[idx].r = 0;
    tr[idx].val = v;
    tr[idx].id = id;
    tr[idx].lazy = 0;
    tr[idx].rnd = rnd_gen();
    return idx;
}

// 下传懒标记 (Lazy Propagation)
// 当我们需要访问子节点时,必须先把当前节点的加法操作传给子节点
void push_down(int p) {
    if (tr[p].lazy) {
        if (tr[p].l) {
            tr[tr[p].l].val += tr[p].lazy;
            tr[tr[p].l].lazy += tr[p].lazy;
        }
        if (tr[p].r) {
            tr[tr[p].r].val += tr[p].lazy;
            tr[tr[p].r].lazy += tr[p].lazy;
        }
        tr[p].lazy = 0; // 标记下传后清零
    }
}

// 核心操作 1: 分裂 (Split)
// 功能:将以 p 为根的树,按值 v 分裂成 x 和 y 两棵树
// x: 所有 val <= v 的节点
// y: 所有 val > v 的节点
void split(int p, long long v, int &x, int &y) {
    if (!p) {
        x = y = 0;  //   细节。。。。
        return;
    }
    push_down(p); // 访问前先下传标记

    if (tr[p].val <= v) {
        x = p; // 当前节点 <= v,属于 x 部分
        // 它的右子树可能有更大的值,继续去分裂右子树
        split(tr[p].r, v, tr[p].r, y);
    } else {
        y = p; // 当前节点 > v,属于 y 部分
        // 它的左子树可能有更小的值,继续去分裂左子树
        split(tr[p].l, v, x, tr[p].l);
    }
}

// 核心操作 2: 合并 (Merge)
// 功能:将 x 和 y 两棵树合并成一棵,返回新根的编号
// 要求:x 中的所有值 必须 <= y 中的所有值 (BST 性质)
void merge(int &p, int x, int y) {
    if (!x || !y) {
        p = x | y;
        return;
    }
    push_down(x); // 合并前也要下传,确保数据准确
    push_down(y);

    // 利用随机优先级决定谁做父节点,保持树的期望深度为 logN
    if (tr[x].rnd < tr[y].rnd) {
        p = x; // x 做根
        merge(tr[p].r, tr[p].r, y); // x 值小,y 拼到 x 的右边
    } else {
        p = y; // y 做根
        merge(tr[p].l, x, tr[p].l); // y 值大,x 拼到 y 的左边
    }
}

练习:https://ac.nowcoder.com/acm/contest/120562/G

练习:https://ac.nowcoder.com/acm/contest/120562/G (26牛客寒假营)

相关推荐
斯内科3 分钟前
四胞胎素数:找出‌个位数分别是 1、3、7、9‌,且‌十位及更高位数字完全相同‌的质数,例如 11、13、17、19
算法·质数·素数·四胞胎素数
Hello.Reader34 分钟前
算法基础(十二)——主方法:快速求解常见递归式
算法
小O的算法实验室1 小时前
2026年IEEE TITS,面向按需外卖配送调度的特定问题知识与基于学习元启发式算法,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
加勒比海带661 小时前
目标检测算法——农林行业数据集汇总附下载链接【Plant】
大数据·图像处理·人工智能·算法·目标检测
洛水水1 小时前
【力扣100题】23. 螺旋矩阵
算法·leetcode·矩阵
影sir1 小时前
不同测试数据下,该如何选择算法
算法·深度优先
潇湘散客2 小时前
CAX软件插件化设计实现牛刀小试
c++·算法·图形学·opengl
速易达网络2 小时前
2026,视觉算法正在经历一场静默革命
算法
WBluuue2 小时前
Codeforces 1094 Div1+2(ABCDE)
c++·算法
TENSORTEC腾视科技2 小时前
腾视科技大模型一体机解决方案:低成本私有化落地,重塑行业智能应用新格局
大数据·人工智能·科技·算法·ai·零售·大模型一体机