一维差分
对于一个数组a[ ],我们构造一个数组b[ ],使得:
a
[
i
]
=
∑
k
=
1
i
b
[
k
]
a[i] = \sum_{k = 1}^ib[k]
a[i]=k=1∑ib[k]
即a[ ]为b[ ]的前缀和。
1. 先思考:将a[ ]中某一段[l, r]之间的数加上c,对于b[ ]的影响如何?
由图可知:由于a[ ]中绿色部分都加上了c,那么对于b[ ]来说:
- 最前面被加的那个数的对应位置要加上c,即b[l] += c。这样在a[ ]求前缀和的时候,l之后的所有元素才会被加上c;
- 同时,由于a[ ]只是r之前的数加了c,r之后的数不变,所以对于b[ ]来说,r之后的第一个数还要减去c,即b[r + 1] -= c。这样才能保证a[r+1]及之后的数不变。
2. 构造差分数组
数组a[ ]可以看成是,每个位置都加上了一个a[i]。因此我们遍历一遍,对b[ ]做n次操作即可构造差分数组:
int main() {
for(int i = 1; i <= n; i ++) {
cin >> a[i];
insert(i, i, a[i]);
}
}
void insert(int l, int r, int c) {// 差分核心操作
b[l] += c;
b[r + 1] -= c;
}
二维差分
对于一个数组a[ ][ ],我们构造一个数组b[ ][ ],使得:
a
[
i
]
[
j
]
=
∑
k
1
=
1
i
∑
k
2
=
1
j
b
[
k
1
]
[
k
2
]
a[i][j] = \sum_{k_1 = 1}^i \sum_{k_2 = 1}^j b[k_1][k_2]
a[i][j]=k1=1∑ik2=1∑jb[k1][k2]
用一维差分类似的方法,可以得到:
int main() {
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]);
}
}
void insert(int x1, int y1, int x2, int y2, int c) {
b[x1][y1] += c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y1] -= c;
b[x2 + 1][y2 + 1] += c;
}