前缀和与差分
前缀和向后,差分向前。
下标都是从1开始
前缀和
一维前缀和:
构造:
S[i] = S[i - 1] + A[i]
求A数组中[l, r]的和:
S[r] - S[l - 1]
二维前缀和:
构造:
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
cin >> A[i][j];
S[i][j] = S[i - 1][j] + S[i][j - 1] + A[i][j] - S[i - 1][j - 1];
}
}
求A数组中[x1, y1]到[x2, y2]之间的和:
S[x2][y2] - S[x1 - 1][y2] - S[x2][y1 - 1] + S[x1 - 1][y1 - 1]
差分
一维差分:
构造:
//insert:给A数组中[l, r]中全部数都加上c
void insert(int l, int r, int c) {
B[l] += c;
B[r + 1] -= c;
}
for(int i = 1; i <= n; i ++) {
cin >> A[i];
insert(i, i, A[i]); //构造A数组的差分数组B
}
最后对差分B数组求前缀和即可得到操作后的A数组:
for(int i = 1; i <= n; i ++) {
A[i] = A[i - 1] + B[i];
}
二维差分:
构造:
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;
}
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
cin >> A[i][j];
insert(i, j, i, j, A[i][j]);
}
}
求A数组:
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
A[i][j] = A[i - 1][j] + A[i][j - 1] + B[i][j] - A[i - 1][j - 1];
}
}
为什么B数组通过insert操作就影响到了A数组呢?
一维:若在B[l]加上c,那么会影响A数组中A[l~last]都会加上c,再从B[r + 1]减去c,那么就能在A数组中[l, r]区域全部加上c,即所谓差分数组是向后影响的。
二维同理。
浙公网安备 33010602011771号