二维前缀和须用容斥原理初始化:dpi = matrixi-1 + dpi-1 + dpi - dpi-1,dp大小为(m+1)×(n+1),查询子矩阵和为dpr2+1 - dpr1 - dpr2+1 + dpr1。

二维前缀和的正确初始化方式
直接套用一维前缀和思路会出错:不能简单对每行先做前缀和再对列做,必须用容斥原理同步更新每个 dp[i][j]。否则区域查询结果偏大或为 0。
核心公式是:dp[i][j] = matrix[i-1][j-1] + dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1],注意下标偏移(通常让 dp 多开一行一列,避免边界判断)。
- 输入矩阵是
matrix,大小为m x n,则dp应声明为vector<vector>>(m+1, vector<int>(n+1))</int></vector> - 循环从
i = 1和j = 1开始,对应访问matrix[i-1][j-1] - 别漏掉减去重叠部分
dp[i-1][j-1],这是最常漏写的项
查询任意子矩阵和的写法与边界检查
查左上角 (r1, c1)、右下角 (r2, c2) 的闭区间和时,公式是:dp[r2+1][c2+1] - dp[r1][c2+1] - dp[r2+1][c1] + dp[r1][c1]。注意:输入坐标是 0-indexed,但 dp 是 1-indexed 偏移设计。
- 如果传入的
r1 == 0或c1 == 0,dp[r1][...]或dp[...][c1]仍合法(因为dp第 0 行/列全为 0) - 务必确保
r2+1 且 <code>c2+1 ,否则越界访问 <code>dp数组 - 不要尝试用
dp[r2][c2] - ...混用 0-indexed 下标,容易多减一行一列
int 溢出与数据类型选择
图像处理中像素值累加极易溢出:1024x1024 的 uint8 图像,最大前缀和可达 1024*1024*255 ≈ 268M,int 通常够用(上限约 2.1G),但若矩阵值本身是 int 或含负数,或尺寸更大(如 4K 图),就可能翻车。
立即学习“C++免费学习笔记(深入)”;
- 保守起见,初始化
dp用long long,尤其当原始数据是int或后续要支持差分更新 - 如果确定值域安全(如 OpenCV 的
CV_8UC1图像),可用int节省内存 - 编译器不会报溢出警告,运行时结果静默错误——这是最难 debug 的点之一
和 OpenCV 的 cv::integral() 对比
OpenCV 的 cv::integral() 默认输出是 CV_32S(有符号 int),但它的定义和手写前缀和一致:输出矩阵第 (i,j) 元素表示原图 [0,i)×[0,j) 区域和(左闭右开)。这和你手写的 dp[i][j](表示 [0,i-1]×[0,j-1] 和)本质相同,只是索引解释略有差异。
- 调用
cv::integral(src, dst)后,查 [r1,c1] 到 [r2,c2](闭区间)需用:dst.at<int>(r2+1,c2+1) - dst.at<int>(r1,c2+1) - dst.at<int>(r2+1,c1) + dst.at<int>(r1,c1)</int></int></int></int> - OpenCV 版本 ≥ 4.5 支持
CV_64F输出类型,可显式指定避免溢出:cv::integral(src, dst, CV_64F) - 自己手写更轻量、可控,但 OpenCV 实现做了 SIMD 优化,大数据量时快 2–3 倍
实际用的时候,最容易卡在坐标偏移和溢出上——前者导致结果差一倍,后者导致结果突然变负,而且都很难一眼看出来。










