S[0] = 0;
for (int i = 1; i <= n; ++i) {
S[i] = S[i - 1] + a[i];
}
[l,r]
的和『 S = S r − S l − 1 S=S_r-S_{l-1} S=Sr−Sl−1』,计算的时间复杂度为 O ( 1 ) O(1) O(1)。S[0][0] = 0; S[0][1] = 0; S[1][0] = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
S[i][j] = S[i - 1][j] + S[i][j - 1] - S[i - 1][j - 1] + a[i][j];
}
[l,r]
区间内的所有数加上一个常数『 c c c』。这一系列操作利用差分的思想可以直接对『 b b b』数组进行时间复杂度为 O ( 1 ) O(1) O(1)的计算即可,具体计算方法是『 b l + c ; b r + 1 − c b_l+c; b_{r+1}-c bl+c;br+1−c』。此时『 b i b_{i} bi』数组的前缀和即为操作后的结果。void insert(int l, int r, int c) {
b[l] += c;
b[r + 1] -= c;
}
void insert(int x1, int y1, int x2, int y2, int c) {
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
(一维前缀和)AcWing 795. 前缀和
#include
using namespace std;
const int N = 100010;
int n, m;
int a[N], s[N];
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
for (int i = 1; i <= n; i ++ ) s[i] = s[i - 1] + a[i]; // 前缀和的初始化
while (m -- ) {
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", s[r] - s[l - 1]); // 区间和的计算
}
return 0;
}
(二维前缀和)AcWing 796. 子矩阵的和
#include
using namespace std;
const int N = 1010;
int n, m, q;
int s[N][N], a[N][N];;
int main() {
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
scanf("%d", &a[i][j]);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]; // 求前缀和
while (q -- ) {
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
printf("%d\n", s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]); // 求子矩阵的和
}
return 0;
}
(一维差分)AcWing 797. 差分
#include
using namespace std;
const int N = 100010;
int n, m;
int a[N], b[N];
void insert(int l, int r, int c) {
b[l] += c;
b[r + 1] -= c;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
for (int i = 1; i <= n; i ++ ) insert(i, i, a[i]); // 这里由于假定初始数组全 0,因此需要先进行预操作
// 这里是题目要求的 m 次操作
while (m -- ) {
int l, r, c;
scanf("%d%d%d", &l, &r, &c);
insert(l, r, c);
}
for (int i = 1; i <= n; i ++ ) b[i] += b[i - 1]; // 求解操作完后 b 数组的前缀和即为答案
for (int i = 1; i <= n; i ++ ) printf("%d ", b[i]);
return 0;
}
(二维差分)AcWing 798. 差分矩阵
#include
using namespace std;
const int N = 1010;
int n, m, q;
int a[N][N], b[N][N];
void insert(int x1, int y1, int x2, int y2, int c) {
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
int main() {
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
scanf("%d", &a[i][j]);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
insert(i, j, i, j, a[i][j]); // 这里由于假定初始数组全 0,因此需要先进行预操作
while (q -- ) {
int x1, y1, x2, y2, c;
cin >> x1 >> y1 >> x2 >> y2 >> c;
insert(x1, y1, x2, y2, c);
}
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1]; // 求解操作完后 b 数组的前缀和即为答案
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= m; j ++ ) printf("%d ", b[i][j]);
puts("");
}
return 0;
}