输入一个 n 行 m 列的整数矩阵,再输入 q 个操作,每个操作包含五个整数 x1,y1,x2,y2,c,其中 (x1,y1) 和 (x2,y2) 表示一个子矩阵的左上角坐标和右下角坐标。
每个操作都要将选中的子矩阵中的每个元素的值加上 c。
请你将进行完所有操作后的矩阵输出。
输入格式
第一行包含整数 n,m,q。
接下来 n 行,每行包含 m 个整数,表示整数矩阵。
接下来 q 行,每行包含 5 个整数 x1,y1,x2,y2,c,表示一个操作。
输出格式
共 n 行,每行 m 个整数,表示所有操作进行完毕后的最终矩阵。
数据范围
1≤n,m≤1000,
1≤q≤100000,
1≤x1≤x2≤n,
1≤y1≤y2≤m,
−1000≤c≤1000,
−1000≤矩阵内元素的值≤1000
输入样例:
3 4 3
1 2 2 1
3 2 2 1
1 1 1 1
1 1 2 2 1
1 3 2 3 2
3 1 3 4 1
输出样例:
2 3 4 1
4 3 4 1
2 2 2 2
方法一:
模板题,对区间的操作就是用差分来做,问题在于怎么定义二维的差分数组以及如何通过二维差分数组对原二维数组进行区间操作
一维差分
复习一下一维差分的定义和性质(a为原数组,b为差分数组):
b[i] = a[i] - a[i-1]
- \(a[i] = \sum_{j=1}^i b[j]\)
其中性质2可由性质1得到
类比一维差分,下面是二维差分的定义:
二维差分
-
\[a[i][j] = \sum_{x=1}^i\sum_{y=1}^j b[x][y] \]a[i][j] = b的前缀和(即矩阵b从 [1, 1] 到 [i, j] 构成的矩阵之和)
-
b[i][j] = a[i][j] + a[i-1][j-1] - a[i][j-1] - a[i-1][j]
其中性质1从性质2得到,结合图下面这张图理解一下(来自https://blog.csdn.net/weixin_45629285/article/details/111146240)
把图中等式移项一下,又由性质1,就得到性质2的等式啦啦啦啦啦。
补充一下:一维差分数组可以直接写出差分数组b的定义,进而得到b前缀和=a元素的性质。而类比到二维差分的时候,发现并不好直接定义差分数组b,而是要类比前缀和的概念,先得到了b前缀和=a元素的性质,再由该性质求出差分数组b
二维区间操作
二维的区间操作肯定也是对差分b进行加减,首先有如下性质
- 对b[i][j]的加减会影响原数组a[i][j]及a[>i][>j]的元素
为了做到对b操作只影响区间[x1][y1]~[x2][y2],进行如下操作(画个图验证一下)
void add(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;
}
讲解完毕~
#include <bits/stdc++.h>
using namespace std;
int n, m, q, X1, Y1, X2, Y2, c;
int matrix[1010][1010];
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", &matrix[i][j]);
}
}
// 原地构造差分矩阵
for (int i = n; i >= 1; i--) {
for (int j = m; j >= 1; j--) {
matrix[i][j] += matrix[i-1][j-1] - matrix[i-1][j] - matrix[i][j-1];
}
}
// 开始操作
for (int i = 0; i < q; i++) {
scanf("%d%d%d%d%d", &X1, &Y1, &X2, &Y2, &c);
matrix[X1][Y1] += c;
matrix[X1][Y2+1] -= c;
matrix[X2+1][Y1] -= c;
matrix[X2+1][Y2+1] += c;
}
// 恢复原矩阵
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
matrix[i][j] += matrix[i-1][j] + matrix[i][j-1] - matrix[i-1][j-1];
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}