AcWing 798 差分矩陣

2021-09-26 02:52:58 字數 3540 閱讀 5489

題目描述:

輸入乙個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

分析:

本題考察二維差分,差分的具體概念見acwing 100 incdec序列。鑑於字首和以及一維差分較為簡單,不再單獨寫題解,簡單的總結下:

一維字首和:設有陣列a[n],s[n]為a的字首和陣列,有s[i] = a[1] + a[2] +... + a[i],有了字首和,我們可以在o(1)的時間內求出任意一段區間內a陣列的和,比如a[l] + a[l + 1] + ... +a[r] = s[r] - s[l - 1].

二維字首和:設有二維陣列a[m][n],s[i][j]為a[i][j]及其之前所有元素的字首和,比如下圖中,從a[1][1]到a[i][j]矩形所有元素的和為s[i][j],s[i - 1][j]表示直線b上邊所有元素的和,s[i][j - 1]表示直線a左邊所有元素之和,則s[i][j] = s[i - 1][j] +s[i][j - 1] - s[i - 1][j -1] + a[i][j],因為a的左邊與b的上邊元素求和時對該區域內元素求了兩遍和,所以需要減去s[i - 1][j - 1].

既然知道了求二維陣列的字首和,那麼求以(x1,y1)為矩形左上角,(x2,y2)為矩形右上角的矩形內所有元素的和可以用公式s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]來計算。如下圖所示,(x2,y2)的字首和減去1左邊的元素之和(s[x1 - 1][y2])再減去2上邊的元素之和(s[x2][y1 - 1])再加上多減去的3區域(s[x1 - 1][y1 - 1]。

一維差分:差分是與字首和相對的概念,設有陣列a[n],b[n],b[n]的字首和陣列為a[n],則b[n]為a[n]的差分陣列,即b[1] = a[1],b[2] = a[2] - a[1],b[3] = a[3] - a[2],...,b[n] = a[n] - a[n - 1].可見把a陣列相鄰兩個元素相見即可得到b陣列,對b陣列求和即可得到a,a[n] = a[1] + a[2] - a[1] + a[3] - a[2] +... + a[n] - a[n - 1] = b[1] + b[2] + ... + b[n]。差分的重要性質就是已知a陣列可以求出b陣列,已知b陣列也可以反推出a陣列。一維字首和使得我們在o(1)的時間內求出區間l到r範圍內元素的和,但是一旦涉及區間更新字首和陣列便沒那麼簡單了,比如對下標1 - 3範圍內的元素都加上2,2 - 4範圍內的元素都加上1,每次進行區間更新,區間中a的每個元素都進行了更新,字首和自然也一直在變。假設有m次區間更新操作,每次對長度為n的區間範圍內的元素都加上乙個數c,一共需要進行m * n次操作才能得到最終的a陣列。差分則是簡化此操作的利器,比如陣列a,下標1 - 10的元素分別為1 2 3 4 5 6 7 8 9 2,對下標為2 - 9的元素都加上3需要進行8次操作,而該操作對a的差分陣列的影響僅僅是b[2] += 3,b[10] -= 3。對區間的操作簡化為了對區間端點的操作,不管區間更新多長,對b陣列的影響始終就兩個元素,m次更新結束,對b陣列一共進行了2m次操作,再利用b求出a問題即可解決。總之,給陣列a[l,r]範圍內的數都加上c的操作等價於b[l] += c,b[r + 1] -= c的操作。

二維差分:經過了這麼多的鋪墊,終於講到了本題的主題二維差分。設有二維陣列a[m][n]及它的差分陣列b[m][n],我們唯一知道的乙個性質就是b的字首和是a,由二維字首和的乙個公式s[i][j] = s[i - 1][j] +s[i][j - 1] - s[i - 1][j -1] + a[i][j]可得,a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + b[i][j],變形得b[i][j] = a[i][j] + a[i - 1][j - 1] - a[i - 1][j] - a[i][j - 1]。等式的右邊可以理解為乙個長度為1的單位矩陣,b[i][j]的值就等於以a[i][j]為右下頂點的正方形的正對角線上兩個端點的和減去副對角線上兩個端點的和。上面的式子對我們理解二維差分尤為重要(但是為啥很少見講二維差分的文章提及),我們可以得出乙個結論,對於二維陣列a,如果a[i][j],a[i - 1][j - 1],a[i - 1][j],a[i][j - 1]都加上c,b[i][j]不變,如果只有一條邊上的兩個端點加上c,比如a[i][j]和a[i][j - 1],b[i][j]的值也不變。那麼對於下圖的矩陣,我們對以(x1,y1)為左上頂點,(x2,y2)為右下頂點的矩形區域內元素都加上c,思考下會改變哪些b陣列的元素,顯而易見,矩形內部的點比如a[x][y](x1

總的**如下:

#include using namespace std;

const int maxn = 1005;

int a[maxn][maxn],b[maxn][maxn];

void insert(int x1,int y1,int x2,int y2,int c)

int main()

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++)

printf("\n");

}return 0;

}

我們在初始化二維差分陣列時,可以直接用上面推導的求b的公式,一般情況下則是直接將a中原有的元素逐個插入,以此來影響b,這樣則不需要要考慮由a推出b的公式了。

AcWing 798 差分矩陣

題目描述 輸入乙個n行m列的整數矩陣,再輸入q個操作,每個操作包含五個整數x1,y1,x2,y2,c,其中 x1,y1 和 x2,y2 表示乙個子矩陣的左上角座標和右下角座標。每個操作都要將選中的子矩陣中的每個元素的值加上c。請你將進行完所有操作後的矩陣輸出。輸入格式 第一行包含整數n,m,q。接下...

AcWing 798 差分矩陣

差分是與字首和互逆的,所以可以用字首和的公式推差分的公式 c i j a i j a i 1 j a i j 1 a i 1 j 1 矩陣加減可以由定義分析,也可以換個思路 a x y sum sum c i j c x y 1 等於把 以 x,y 為左上角 n,m 為右下角的矩陣中的 a i j ...

ACwing 798 差分矩陣

不得不說之前的差分我真的是掌握的不好。一維差分確實簡單一看就會,但是學會了之後卻並不能靈活的運用。而二維的差分我甚至還琢磨了很長時間 顧名思義,就是在矩陣中,一行 一列 的元素與上一行 上一列 對應元素的差值,依次排列在上一行 上一列 元素對應所在位置。好像說的是矩陣差分,但是問題不大 但是只要你用...