题目链接:
https://www.acwing.com/problem/content/description/800/
思路: 用差分的思想,将区间修改转换为单点修改
假设原始的数字矩阵为a[n][m], 为了使用差分,我们构造相应的差分矩阵b[n][m]。
令矩阵b满足: a[i][j]=b[1~i][1~j](i.e. )
b[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1].
故: a[i][j]就是矩阵b的一个二维前缀和
接下来我们考虑题目中的更新: 要对(x1,y1) 到(x2,y2)这个矩形中的所有a[i][j]都增加c
我们考虑用以下对差分矩阵b的操作来替代直接对原始矩阵a的操作:
b[x1][y1]+=c;
b[x2+1][y1]-=c;
b[x1][y2+1]-=c;
b[x2+1][y2+1]+=c;
简单分析不难证明这样子的操作和原始直接修改矩阵a是等价的。
通过这样子对差分矩阵进行修改,我们就可以将原本单次修改的O(n方)复杂度变换为单次修改的O(1)复杂度。
最后,需要考虑一下矩阵b如何初始化。
因为我们并没有得到b[i][j]的算术表达式,故其实不是很好直接给他一个初始值。
但是我们可以使用一个技巧,就是认为矩阵a原本全是0,矩阵b也原本全是0.
然后将a[i][j]的初始值看作是对矩阵a的单点修改。这样就可以巧妙地利用上面对矩阵b的修改操作来实现矩阵b的“初始化”
#include<iostream>
#include<cstring>
using namespace std;
const int N=1010;
int a[N][N],b[N][N];
int n,m,q;
void update(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;
return ;
}
int main(void){
scanf("%d%d%d",&n,&m,&q);
int x;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&x);
update(i,j,i,j,x);
}
}
while(q--){
int x1,y1,x2,y2,c;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c);
update(x1,y1,x2,y2,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]+b[i][j];
printf("%d",a[i][j]);
if(j!=m) printf(" ");
else printf("\n");
}
}
return 0;
}