一维前缀和中prefix[i]定义为arr[0]到arr[i-1]的和,是为了使区间[l,r]和统一表示为prefix[r+1]-prefix[l],避免l=0时的边界判断;初始化vector prefix(n+1),prefix[0]=0,循环i∈[0,n)计算prefix[i+1]=prefix[i]+arr[i]。

一维前缀和:为什么 prefix[i] 要定义为前 i 个元素和(含 arr[0] 到 arr[i-1])?
因为这样能避免每次查询都做边界判断。若定义 prefix[i] = arr[0] + ... + arr[i],则区间 [l, r] 和需写成 prefix[r] - (l > 0 ? prefix[l-1] : 0);而标准定义下 prefix[0] = 0,prefix[i] = arr[0] + ... + arr[i-1],查询直接用 prefix[r+1] - prefix[l],无分支、无越界风险。
实操建议:
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 初始化时用
vector<long long> prefix(n + 1)</long>,长度比原数组多 1 - 构建用循环:
for (int i = 0; i - 查区间
[l, r](0-indexed):直接返回prefix[r + 1] - prefix[l] - 注意溢出:原始数组若为
int,累加过程必须用long long存prefix
二维前缀和:为什么 sum[i][j] 表示以 (0,0) 为顶点、(i-1,j-1) 为右下角的矩形和?
和一维同理,是为了统一处理边界。这个定义下,任意子矩阵 [r1, c1] 到 [r2, c2](闭区间)的和为:sum[r2+1][c2+1] - sum[r1][c2+1] - sum[r2+1][c1] + sum[r1][c1]。所有下标都不需要条件判断。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 声明二维
prefix时用vector<vector long>> prefix(h + 1, vector<long long>(w + 1))</long></vector> - 构建时三重逻辑不能错:
prefix[i+1][j+1] = prefix[i][j+1] + prefix[i+1][j] - prefix[i][j] + mat[i][j]; - 查矩形和时务必确认输入坐标是闭区间,且
r1 、<code>c1 ,否则结果无意义 - 不要试图复用原数组空间:原地计算会破坏后续依赖项,必须开新二维数组
多次修改 + 查询场景下,前缀和还高效吗?
不高效。前缀和本质是静态预处理结构,单次修改代价是 O(n)(一维)或 O(h×w)(二维)。哪怕只改一个元素,整个 prefix 数组都得重算。
替代方案取决于修改频率:
- 修改极少(≤ 10 次)、查询极多 → 仍可用前缀和,每次修改后全量重建
- 修改频繁 → 改用
std::vector配合std::accumulate临时算(小数组)或换树状数组(BIT)/线段树 - 二维且修改多 → 几乎必须上二维 BIT 或动态开点线段树,没有“轻量级”替代
注意:std::partial_sum 只是一维前缀和构造工具,不解决修改问题;它生成的是只读数组,不带更新能力。
边界与索引错位:调试时最常卡在哪几个地方?
几乎所有 bug 都来自下标偏移没对齐。典型错误现象:segmentation fault、结果差一个元素、查询 [0,0] 返回 0 而不是 arr[0]。
检查清单:
- 构建前缀数组长度是否为
n + 1(一维)或(h + 1) × (w + 1)(二维) - 循环中访问
arr[i]时,对应prefix[i + 1]是否越界(如i == n时i + 1会超) - 二维查询时,四个角坐标是否全部 +1 后再代入公式(
r1, c1, r2, c2都要 +1) - 输入坐标是否已确认是 0-indexed?有些题目给的是 1-indexed 区间,需先减 1
真正容易被忽略的,是混合使用原始数组和前缀数组时的索引混用——比如在查询逻辑里误把 prefix[l] 当成 arr[l] 用,这种 bug 编译器不报错,但结果完全不可预测。

















