前缀和数组应初始化为长度n+1,sum[0]=0,递推式为sum[i]=sum[i-1]+a[i-1](i从1到n);查询[l,r]用sum[r+1]-sum[l],二维同理需容斥且数组大小为(n+1)×(m+1)。

前缀和数组怎么初始化才不会越界
初始化时下标从 1 开始最省心,避免 sum[0] 和原数组 a[0] 对齐导致的边界混淆。C++ 中常见错误是把前缀和长度设成 n 却用 sum[i] = sum[i-1] + a[i-1],结果访问 a[-1] 或漏算最后一个元素。
- 原数组长度为
n,前缀和数组长度应为n+1,sum[0] = 0 - 递推写成
sum[i] = sum[i-1] + a[i-1](i从 1 到n) - 别用
vector<int> sum(a)</int>原地构造——那是复制,不是前缀和
查询 [l, r] 区间和为什么用 sum[r+1] - sum[l]
因为 sum[i] 定义为前 i 个元素之和(即 a[0] 到 a[i-1]),所以 sum[r+1] 覆盖 [0, r],sum[l] 覆盖 [0, l-1],相减正好得 [l, r]。用 sum[r] - sum[l-1] 看似对称,但极易在 l == 0 时访问 sum[-1],崩溃或返回随机值。
- 统一用左闭右闭区间输入,代码里转成
sum[r+1] - sum[l] - 如果输入是 1-indexed(比如题目说“第1个到第5个”),直接对应
sum[5] - sum[0],不用额外减1 - 别为了“看着顺”强行改成 0-indexed 查询逻辑——增加条件分支反而易错
二维前缀和的递推式为什么是 sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i-1][j-1]
这是容斥原理:上边 + 左边会把左上角区域重复加了一次,必须减掉。下标偏移和一维一样——sum[i][j] 表示从 a[0][0] 到 a[i-1][j-1] 的和。漏减 sum[i-1][j-1] 是高频错误,会导致查询结果偏大。
- 二维
sum数组大小必须是(n+1) × (m+1),首行首列全 0 - 初始化循环从
i = 1到n,j = 1到m,别用0起始 - 查子矩阵
[r1, c1]到[r2, c2](闭区间)用:sum[r2+1][c2+1] - sum[r1][c2+1] - sum[r2+1][c1] + sum[r1][c1]
前缀和能处理修改吗?什么情况下必须换树状数组
纯前缀和只适合静态数组。一旦有单点修改,每次都要 O(n) 重算整个 sum 数组,比暴力还慢。这时候就得上 std::vector 配合 BIT(树状数组)或 SegmentTree。
立即学习“C++免费学习笔记(深入)”;
- 如果只有 1 次修改 + 多次查询,重算前缀和可以接受;超过 3 次修改就该换结构了
-
BIT支持单点改、区间查,代码短、常数小,update(i, delta)和query(r) - query(l-1)就够用 - 别试图用
std::partial_sum动态更新——它只是生成一次前缀和,不维护状态
前缀和真正的坑不在写法,而在误判使用场景:以为“预处理了就能应对修改”,结果在循环里反复调用 partial_sum,性能雪崩。










