前缀和

前缀和是一种重要的预处理,能大大降低查询的时间复杂度。可以简单理解为:数列的前n项的和

一维前缀和

B[i] = B[i-1] + A[i]

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N = 10010;
  4. int a[N],b[N],n;
  5. int main()
  6. {
  7. cin >> n;
  8. for (int i = 1;i <= n;i ++) {
  9. cin >> a[i];
  10. }
  11. for (int i = 1;i <= n;i ++) {
  12. // 前缀和数组的第i项 = 原数组的 0 到 i-1 项的和 + 原数组的第 i 项
  13. b[i] = b[i-1] + a[i];
  14. }
  15. for (int i = 1;i <= n;i ++) {
  16. cout << b[i] << " ";
  17. }
  18. return 0;
  19. }

二维前缀和

基于容斥原理
S[i,j] = S[i-1,j] + S[i,j-1] - S[i-1,j-1] + A[i,j]

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N = 10010;
  4. int a[N][N],b[N][N],n,m;
  5. int main()
  6. {
  7. cin >> n >> m;
  8. for (int i = 1;i <= n;i ++) {
  9. for (int j = 1;j <= m;j ++) {
  10. cin >> a[i][j];
  11. }
  12. }
  13. for (int i = 1;i <= n;i ++) {
  14. for (int j = 1;j <= m;j ++) {
  15. b[i][j] = b[i-1][j] + b[i][j-1] - b[i-1][j-1] + a[i][j];
  16. }
  17. }
  18. for(int i = 1;i <= n;i ++ ) {
  19. for(int j = 1;j <= m;j++ ) {
  20. cout << b[i][j] << " ";
  21. }
  22. cout << endl;
  23. }
  24. return 0;
  25. }

(x1,y1) - (x2,y2) = S[x2,y2] - S[x1-1,y2] - S[x2,y1-1] + S[x1-1,y1-1]

差分

差分是一种和前缀和相对的策略,可以当做是求和的逆运算
给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c

给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c