线段树数组大小至少开4×n,因最坏情况下需补全为满二叉树,叶子层最多2n个节点,总节点数上限约4n;不足会导致越界访问、段错误或随机值。

线段树构建时数组大小为什么至少要开 4×n
因为线段树是二叉树结构,最坏情况下(n 不是 2 的幂)需要补全到最近的满二叉树。叶子层最多有 2×n 个位置,整棵树节点数上限约 2×(2×n)−1 ≈ 4×n。开 4 * n 是稳妥做法,少于这个值在查询或更新时容易越界访问。
常见错误现象:Segmentation fault 或返回随机值,尤其在 n 接近边界(如 1e5)时才暴露。
- 若用 vector 动态分配,直接声明
vector<int> tree(4 * n)</int> - 静态数组慎用
int tree[100005]—— 这只够存原始数组,不是线段树 - 构建前先确认输入
n,再按4 * n分配空间,别用估算值
build() 函数里 mid 计算必须用 (l + r) / 2 还是 l + (r - l) / 2
两者等价,但 l + (r - l) / 2 更安全,避免 l + r 溢出(尤其当 l、r 接近 INT_MAX 时)。不过在 RMQ 场景中,下标一般来自数组长度(≤ 1e6),用 (l + r) / 2 没问题;但写成 l + (r - l) / 2 是更普适的习惯。
注意:必须用整数除法,C++ 中 / 对整型自动向下取整,符合要求。
- 子区间划分必须严格满足:
[l, mid]和[mid + 1, r],不能漏掉或重叠 - 递归终止条件是
l == r,此时tree[node] = arr[l] - 回溯赋值逻辑是
tree[node] = max(tree[left], tree[right])
query(l, r) 查询时为什么常写成 query(1, 0, n-1, ql, qr)
这是标准线段树封装方式:1 是根节点编号(1-indexed 树),0 和 n-1 是当前节点覆盖的原始区间,ql、qr 是用户请求的查询区间。四参数接口把“当前遍历状态”和“用户需求”分离,避免全局变量或重复计算。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
容易踩的坑:传错初始区间(比如写成 query(1, 1, n, ql, qr) 却没调整 arr 下标),导致结果偏移或越界。
- 所有递归调用中,当前节点覆盖区间始终是
[tl, tr],不是固定值 - 三种情况需分别处理:完全不交 → 返回极小值;完全包含 → 直接返回
tree[node];部分重叠 → 递归查左右子树再max - 极小值建议用
INT_MIN,别用0或-1,否则负数数组会出错
单点修改 update(pos, val) 后为什么必须从叶子向上 push up
线段树维护的是区间信息(这里是最大值),修改一个叶子后,所有包含它的祖先节点的 tree[node] 都可能失效。必须从该叶子一路回溯到根,逐层重新计算 max。跳过某一层会导致后续查询返回旧值。
性能影响:单次修改时间复杂度是 O(log n),路径长度就是树高;如果误写成 DFS 全局重 build,就退化成 O(n),完全失去线段树意义。
- update 参数通常是
(node, tl, tr, pos, val),先定位到叶子(tl == tr == pos),再向上回溯 - 回溯时用
tree[node] = max(tree[left_node], tree[right_node]),左右子节点编号为2*node和2*node+1 - 别忘了检查
pos是否在[tl, tr]内,不在则直接 return
实际写的时候,build 和 query 的边界判断稍有不慎就会漏一个元素或进死循环。最常被忽略的是:查询区间 [ql, qr] 是用户给的闭区间,而递归中每次切分也必须保持闭区间语义 —— 这一点错一点,整个结果就不可靠。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










