Day4整理的時候忘了這一塊了。。我現在補上它。
並不難理解。
前綴和
其實可以把它理解為數學上的數列的前n項和(對於一個一維數組的前綴和)。
我們定義對於一個數組a的前綴和數組s,s[i] = a[1]+a[2]+...+a[i].
二維前綴和
與一維前綴和類似,設s[i][j]表示所有a[i'][j']的和。(1≤i'≤i,1≤j'≤j)
有一點像“矩形的面積”那樣,把一整塊區域的值都加起來。
前綴和的用途
一般用來求區間和。
對於一維情況,現在我給出一個數列a,要求你回答m次詢問,每次詢問下標j到k的和。朴素的做法顯然是對於每次詢問都執行一次相加操作,然后輸出結果。這樣做是正確的,但是當m過大時就會導致計算次數過多而有可能超時。
超時的原因一目了然,重復計算。那么我們應該怎么改進這個方法呢?想象一下,我們如果先提前算好了每一個位置的前綴和,然后用s[k]-s[j],結果不就是我們這次詢問的答案嗎?這樣便會使計算量大大減小。
對於二維的區間和,也是類似的。
我們借助這個圖片研究一下。假設在這個矩陣(二維數組)中,我們要求和的是上圖中紅色區域。現在我們已經預處理出了所有點的前綴和,現在給定兩個點(x1,y1),(x2,y2),我們要求 以這兩個點連線為對角線的一個子矩陣的數值之和。暴力做法直接挨個加這個我就不再多說了,反正早晚都得TLE,我們重點考慮用前綴和的快速做法。
首先我們可以把s[x2][y2]求出來,它代表整個大矩形的前綴和,然后我們分別減去它左邊多出來的一塊的前綴和和下邊多出來一塊的前綴和,這樣就是最終答案了?
不是!這不是最終答案。可以發現,在我們剪掉這兩個多出的區域時,下邊的一小塊被減了兩次,但減兩次顯然是不合理的,我們應該加回來。。
所以對於一次的查詢答案ans應該等於
s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]。
這個二維前綴和也稱差分序列。
用差分實現區間操作
給定一個長度為n的數列a,要求支持操作add(L,R,k)表示對a[L]~a[R]的每個數都加上k。並求修改后的序列a。
暴力做法顯然,TLE,下一個。
我們考慮用差分的做法。這里 需要一個輔助數組c,c用來記錄某一個位置上的總改變量。c[i]表示的是i~n這些元素都加上c[i]這個數。我們對[L,R]區間進行加值操作,在c[L]處加一個k,在c[R+1]處就減去一個k。最后求序列的每個位置變成了多少,只需要求一下c數組的前綴和,然后和原數組按位相加就好。
這個結論的證明我不是太會。。呃記住它是對的就好啦。。
對於二維的情況,一個n*m的矩陣,要求支持操作add(x1,y1,x2,y2,a),表示對於以(x1,y1)為左下角,(x2,y2)為右上角的矩形區域,每個元素都加上a。要求修改后的矩陣。
我們的做法和一維類似。用數組c存儲總改變量。在c[x1][y1]處加上a,在c[x2+1][y1]和c[x1][y2+1]處減a,在c[x2+1][y2+1]再加上a。最后(i,k)位置上的數值就是c數組在(i,k)位置的前綴和。
