线段树查询区间最大值的正确方法是递归拆分区间并合并子结果:若当前节点区间完全在目标内则直接返回max_val,无交集返回int_min,否则递归左右子树取max;须避免单点查询拼接导致o(n)退化。

线段树查询区间最大值:用 query_max 递归收缩区间
线段树查区间最大值的核心是「区间拆分 + 合并子结果」,不能直接访问叶子再遍历比较。典型错误是写成单点查询拼接,导致时间退化到 O(n)。
正确做法是在每个节点维护 max_val,查询时根据当前节点区间 [l, r] 与目标区间 [ql, qr] 的关系分支处理:
- 若
[l, r]完全在[ql, qr]内,直接返回tree[node].max_val - 若完全无交集,返回
INT_MIN(或LLONG_MIN,注意类型) - 否则递归查左右子树,返回
max(left_result, right_result)
注意:合并时必须用 max,不是 +;且初始调用要确保 ql ,否则可能无限递归或越界。
线段树查询区间和:query_sum 要区分懒标记是否下传
区间和查询本身逻辑简单,但实际中几乎总和区间更新共存——一旦支持「区间加」或「区间赋值」,就必须处理懒标记(lazy tag)。常见崩溃点是:查和前没调用 push_down,导致子节点数据陈旧。
关键步骤顺序不能错:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 进入节点第一件事:检查
tree[node].lazy != 0(或非空),立即push_down(node, l, r) - 然后才判断区间覆盖关系
- 若完全覆盖,直接返回
tree[node].sum;否则递归左右子树并相加
示例片段(伪代码):
if (ql > 1; long long res = 0; if (ql mid) res += query_sum(rs(node), mid+1, r, ql, qr); return res;
最大值与和共存:一个结构体里同时存 max_val 和 sum
不需要建两棵线段树。多数场景下,把两个值塞进同一个节点结构体更省空间、易维护:
struct Node {
long long sum;
int max_val;
int lazy; // 若只支持加法,int 足够
};
这样每次 push_up 就要同步更新两个字段:tree[node].sum = tree[ls].sum + tree[rs].sum;tree[node].max_val = max(tree[ls].max_val, tree[rs].max_val);
注意点:
- 若 max_val 可能为负,初始化叶子节点时别用 0 覆盖原数组负值
- sum 用 long long 是底线,int 在 1e5 数据量下极易溢出
- 懒标记类型要和操作语义一致:区间加用 int,区间赋值建议用 pair<bool int></bool> 或额外标志位
调试时最常卡住的三个位置
写完跑不对?先盯死这三处:
- 下标从
0还是1开始建树?build(1, 0, n-1)和build(1, 1, n)对应的ls/rs计算方式不同,容易越界访问tree[2*node] -
push_down里更新子节点sum和max_val时,是否漏了对max_val加懒值?比如区间加操作,子节点max_val也要加lazy,不是只加sum - 查询函数参数传反:把
query_max(1, 0, n-1, l, r)写成query_max(1, 0, n-1, r, l),尤其当l > r时可能触发未定义行为
线段树的复杂度不在原理,而在边界和状态同步。哪怕多加两行 assert(l
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










