1. 程式人生 > 實用技巧 >二維差分

二維差分

二維差分

我們有一個矩陣,如下圖所示:

假設我們有這麼一個矩陣:

1 2 4 3
5 1 2 4
6 3 5 9

二維字首和公式:

 sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+arr[i][j];

差分:

如果我們要在左上角是 (x1,y1),右下角是 (x2,y2) 的矩形區間每個值都 +a,如下圖所示

在我們要的區間開始位置(x1,y1)處 +c,根據字首和的性質,那麼它影響的就是整個黃色部分,多影響了兩個藍色部分,所以在兩個藍色部分 -c 消除 +c 的影響,

而兩個藍色部分重疊的綠色部分多了個 -c 的影響,所以綠色部分 +c 消除影響。所以對應的計算方法如下:

diff[x1][y1] += c;
diff[x1][y2+1] -=c;
diff[x2+1][y1] -=c;
diff[x2+1][y2+1] += c;

差分矩陣:

diff[i][j]=arr[i][j]-arr[i-1][j]-arr[i][j-1]+arr[i-1][j-1];

差分陣列為:

1 1 2 -1
4 -5 -1 3
1 1 1 2
-6 3 -2 -4

求區間值:

要求左上角是(x1,y1),右下角是(x2,y2)的矩形區間內的值處理出字首和後也可以O(1)時間內求出來。

我們要求紫色部分的值,我們已知的是黃色部分的值,但它多了兩個藍色部分的值,而兩個藍色部分有重疊了個綠色部分

sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1]

例題:

題目描述

輸入一個 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 個整數,表示所有操作進行完畢後的最終矩陣。

程式碼:

#include<bits/stdc++.h>
#include<algorithm>
#include<cstring>
using namespace std;


const int MAXN = 1e3+6;
const int MAXM = 1e3+6;
int a[MAXN][MAXM] = {};
int diff[MAXN][MAXM] = {};
 
int main() {
    int n,m,q;
    freopen("data1.txt","r",stdin);
    cin>>n>>m>>q;
    int i, j;
    for (i=1; i<=n; i++) {
        for (j=1; j<=m; j++) {
            cin>>a[i][j];
            diff[i][j] = a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1];
        }
    }
    for (i=0; i<q; i++) {
        int x1, y1, x2, y2, c;
        cin>>x1>>y1>>x2>>y2>>c;
        diff[x1][y1] += c;
        diff[x1][y2+1] -=c;
        diff[x2+1][y1] -=c;
        diff[x2+1][y2+1] += c;
    }
    for (i=1; i<=n; i++) {
        for (j=1; j<=m; j++) {
            diff[i][j] += diff[i-1][j]+diff[i][j-1]-diff[i-1][j-1];
            cout<<diff[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}