差分矩阵 AcWing

题目链接:  

798. 差分矩阵 - AcWing题库

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. \sum_{k=1}^{i}\sum_{t=1}^{j}b[k][t])

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;
}

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值