目录
1.一维差分
- 核心思想
差分简单来说就是相邻元素的差值。
- 核心作用📍📍📍
对原数组
a
的一个区间[l, r]
进行加c
的操作,等价于对差分数组d
的d[l]
加c
,d[r + 1]
减c
。通过这种方式,将对原数组区间的操作转化为对差分数组的单点操作,从而提高操作效率。(减法同理)
- 核心代码
差分的实现步骤🌻
- 构造差分数组:遍历原数组,根据差分的定义计算差分数组的每个元素。
- 区间操作:对原数组的区间
[l, r]
进行加c
的操作时,将差分数组的d[l]
加c
,d[r + 1]
减c
。- 还原原数组:通过差分数组还原原数组,即
a[i] = d[0] + d[1] +... + d[i]
,可以使用前缀和的方式计算。
//n是数组元素个数,m是操作个数, d数组为差分数组
//构造差分数组
for (int i = 1; i <= n; i++) {
cin >> a[i];
d[i] = a[i] - a[i - 1];
}
//区间加减操作
for (int i = 1; i <= m; i++) {
int l, r, c;
cin >> l >> r >> c;
d[l] += c;
d[r + 1] -= c;
}
//切记:更新原始数组⚠️⚠️⚠️
for (int i = 1; i <= n; i++) {
a[i] = a[i - 1] + d[i];
cout << a[i] << ' ';
}
2.二维差分
- 核心思想
二维差分的核心思想是通过记录二维数组中相邻元素的差值,将对原数组的子矩阵操作转化为对差分数组中对应元素的操作,以达到高效处理区间修改问题的目的。
- 核心作用📍📍📍
🌻具体来说,当需要对原二维数组中的某个子矩阵进行修改时,如对以\((x_1, y_1)\)为左上角、\((x_2, y_2)\)为右下角的子矩阵的每个元素都加上常数c,只需要在差分数组的四个关键位置\((x_1, y_1)\)、\((x_1, y_2 + 1)\)、\((x_2 + 1, y_1)\)、\((x_2 + 1, y_2 + 1)\)进行相应的加减操作即可。
图示:
- 核心代码
2.1 构造二维差分数组
如果已知原二维数组 \(a_{i,j}\),可以通过如下方式构造差分数组 \(b_{i,j}\):
- \(b_{i,j}=a_{i,j}-a_{i - 1,j}-a_{i,j - 1}+a_{i - 1,j - 1}\)
2.2 子矩阵修改
若要对原二维数组中以 \((x_1,y_1)\) 为左上角、\((x_2,y_2)\) 为右下角的子矩阵的每个元素都加上常数 c,只需对差分数组进行如下操作:
- \(b_{x_1,y_1}+=c\)
- \(b_{x_1,y_2 + 1}-=c\)
- \(b_{x_2+1,y_1}-=c\)
- \(b_{x_2 + 1,y_2+1}+=c\)
2.3 从差分数组还原原数组
可以通过对差分数组求二维前缀和来还原原数组,公式为:
- \(a_{i,j}=a_{i - 1,j}+a_{i,j - 1}-a_{i - 1,j - 1}+b_{i,j}\)
//构造二维差分数组
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
d[i][j] = a[i][j] - a[i][j - 1] - a[i - 1][j] + a[i - 1][j - 1];
}
}
//子矩阵加减操作
for (int i = 0; i < q; i++) {
int x1, y1, x2, y2, c;
cin >> x1 >> y1 >> x2 >> y2 >> c;
d[x1][y1] += c;
d[x2 + 1][y1] -= c;
d[x1][y2 + 1] -= c;
d[x2 + 1][y2 + 1] += c;
}
//切记:更新原二维数组⚠️⚠️⚠️
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] - a[i - 1][j - 1] + d[i][j];
cout << a[i][j] << ' ';
}
cout << endl;
}
}