差分矩阵(二维差分)

一、算法描述

上一篇文章介绍了一维差分,本篇文章来介绍一下什么是二维差分。

含义

  • 显然一维差分是一维前缀和的原数组,那么二维差分就是二维前缀和的原数组。

怎么求

  • 跟一维一样,插入一遍即可,但是要注意每次插入要在同一个位置内插入,insert(i, j, i, j, a[i][j]);

怎么用

  • 一维差分是使得数组 a[n][l,r] 范围内的数都加上 c ,那么二维差分的作用就是使得 a[n][n](x1,y1)(x2,y2) 范围内的数都加上 c

  • 差分操作的都是原数组 b ,通过 b 求一遍前缀和才能得到 a ,也要注意我们操作的都是差分数组 b ,那么我们如何操作 b 才能得到上面的效果呢?

  • 首先b[x1][y1] += c;,这样就会使得 (x1,y1) 到右下角所有的数都加上 c ,然后有一些是不需要加但是加了的,所以要减回来,b[x2 + 1][y1] -= c, b[x1][y2 + 1] -= c;,这样操作之后右下角有一块减了两次,所以还要再加回来一次,b[x2 + 1][y2 + 1] += c;,这样就可以达到效果了,建议读者在草稿纸上画一下,更好理解。

代码如下:

void insert(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;
}

二、题目描述

输入一个 nm 列的整数矩阵,再输入 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 个整数,表示所有操作进行完毕后的最终矩阵。

数据范围

1n,m1000,
1q100000,
1x1x2n,
1y1y2m,
1000c1000,
10001000

输入样例:

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 

三、题目来源

AcWing算法基础课-798.差分矩阵

四、源代码

#include <iostream>

using namespace std;

const int N = 1010;

int n, m, q;
int a[N][N], b[N][N];

void insert(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;
}

int main()
{
    cin >> n >> m >> q;
    
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            cin >> a[i][j];
            
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            insert(i, j, i, j, a[i][j]);
            
    while (q -- )
    {
        int x1, y1, x2, y2, c;
        cin >> x1 >> y1 >> x2 >> y2 >> c;
        
        insert(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];
            
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= m; ++j)    cout << a[i][j] << ' ';
        cout << endl;
    }
    
    return 0;
}
posted @   grave-master  阅读(1166)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示