前缀和数组应声明为长度比原数组多1且prefix[0]=0,例如原数组{1,2,3,4}时定义prefix(5)并令prefix[0]=0,再通过prefix[i]=prefix[i-1]+arr[i-1]递推填充。

前缀和数组怎么初始化才不会越界
初始化前缀和数组时,最常见错误是把 prefix[0] 直接设为原数组首元素,导致后续所有区间查询偏移一位。正确做法是让 prefix 长度比原数组多 1,且 prefix[0] = 0,这样 prefix[i] 表示前 i 个元素(下标 0 到 i-1)的和。
实操建议:
- 若原数组为
vector<int> arr = {1, 2, 3, 4}</int>,则声明vector<long long> prefix(arr.size() + 1)</long> - 用循环:
for (int i = 0; i - 务必用
long long存储前缀和,避免大数组累加溢出(int在约 2e5 个 1e4 元素时就可能溢出)
查询 [l, r] 区间和为什么写成 prefix[r+1] - prefix[l]
因为 prefix[i] 定义为前 i 个元素之和(即索引 0 ~ i-1),所以:
-
prefix[r + 1]是前r + 1个元素和 → 等价于arr[0]到arr[r] -
prefix[l]是前l个元素和 → 等价于arr[0]到arr[l - 1] - 相减后剩下
arr[l]到arr[r]的和,正好是闭区间 [l, r]
如果误写成 prefix[r] - prefix[l-1],当 l == 0 时会访问 prefix[-1] —— 这是未定义行为,调试器不一定报错但结果随机。
二维前缀和的递推式别记混:prefix[i][j] = prefix[i-1][j] + prefix[i][j-1] - prefix[i-1][j-1] + matrix[i-1][j-1]
二维前缀和本质是容斥原理。关键点在于:左上角子矩阵被加了两次,必须减一次;而当前元素只应加一次,但它在原始矩阵中位于 (i-1, j-1),所以右边最后一项是 matrix[i-1][j-1],不是 matrix[i][j]。
常见错误现象:
- 结果整体偏大 → 多加了某个区域,大概率是漏减
prefix[i-1][j-1] - 查询时返回负数或异常值 → 初始化没设
prefix[0][*] = 0和prefix[*][0] = 0,导致越界读取垃圾值 - 查询 [r1, c1] 到 [r2, c2] 闭区间和,公式是:
prefix[r2+1][c2+1] - prefix[r1][c2+1] - prefix[r2+1][c1] + prefix[r1][c1],四个角的位置必须严格对应“多一”的定义
前缀和不支持修改?那需要动态更新怎么办
标准前缀和一旦构建完成,原数组任意位置修改都会让整个 prefix 失效——重算时间复杂度是 O(n),失去预处理意义。这不是 bug,是设计使然。
如果业务中存在频繁单点修改 + 区间查询,应该换数据结构:
- 用
std::vector手动维护前缀和?不行,每次改一个点都要 O(n) 更新后面所有项 - 改用
Fenwick Tree(树状数组):单点修改 O(log n),区间查询 O(log n),代码量少、常数小,适合大多数场景 - 或者
Segment Tree(线段树):支持更复杂操作(如区间加、区间最值),但编码稍重 - 别试图在前缀和基础上“打补丁”,比如只更新受影响部分——逻辑极易出错,且边界条件比树状数组还难缠
真正容易被忽略的是:前缀和的价值不在“万能”,而在“极简”——它只适合静态数组 + 高频查询这种明确场景。一旦有修改,立刻切换思路,而不是硬套模板。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











