我們定義對於一個數組$a[]$的前綴和數組$s$,$s[i] = a[1]+a[2]+...+a[i]$.
前綴和的用途
現在給出一個數列$a$,要求回答$m$次詢問,每次詢問下標$l$到$r$的和
朴素的做法顯然是對於每次詢問都執行一次相加操作,然后輸出結果。這樣做是正確的,但是當$m$過大時就會導致計算次數過多而有可能超時。
超時的原因一目了然,重復計算。那么我們應該怎么改進這個方法呢?
想象一下,我們如果先提前算好了每一個位置的前綴和,然后用$s[r]-s[l-1]$,結果不就是我們這次詢問的答案嗎?這樣便會使計算量大大減小。
對於二維的區間和,也是類似的

首先我們可以把$s[x2][y2]$求出來,它代表整個大矩形的前綴和,然后我們分別減去它左邊多出來的一塊的前綴和和下邊多出來一塊的前綴和,這樣就是最終答案了?
不是!這不是最終答案。可以發現,在我們剪掉這兩個多出的區域時,下邊的一小塊被減了兩次,但減兩次顯然是不合理的,我們應該加回來。
給定一個長度為$n$的數列a,有$q$個操作,每次操作給定$l,r,x$表示$[l,r]$區間所有的數都加上$x$。並求修改后的序列$a$。
之所以叫做差分,是因為我們需要維護的數據是“相鄰兩個數之差”。
差分數組不僅僅是一個優秀的數據結構,還是一種很好的思想
差分數組的功能是修改區間,查詢點。修改區間的時間復雜度是$O(1)$,查詢點的時間復雜度為$O(n)$
我們這里要根據數據范圍靈活選取方法,不要拘泥於差分數組
void update(int l,int r,int x) { c[l]+=x; c[r+1]-=x; }
以上是修改區間操作,$l$位置加上修改量,$r+1$位置減去修改量,這樣整個區間的元素就相當於修改了
int sum(int x) { int ans=0; for(int i=1;i<=x;i++) ans+=c[i]; return ans; }
剛才修改方便了不少,但是查詢的時候就需要全部都加一遍了
還有就是預處理的時候
c[1]=a[1]; for(int i=2;i<=n;i++) c[i]=a[i]-a[i-1];
對於二維的情況
給定一個$n\ast m$的矩陣,要求支持操作$add(x1,y1,x2,y2,a)$,表示對於以$(x1,y1)$為左上角,$(x2,y2)$為右下角的矩形區域,每個元素都加上$a$。要求修改后的矩陣。
類比二維前綴和和一維差分,可以簡單推測出二維差分的公式
$c[i][j]=a[i][j]−a[i−1][j]−a[i][j−1]+a[i−1][j−1]$
我們再代入檢驗,即將左上角的矩陣差分求和,正好得到了這個數
如果我們要在左上角是$(x1,y1)$,右下角是$(x2,y2)$的矩形區間每個值都$+a$
在我們要的區間開始位置$(x1,y1)$處$+a$,根據前綴和的性質,那么它影響的就是整個黃色部分,多影響了兩個藍色部分,所以在兩個藍色部分$-a$消除$+a$的影響,而兩個藍色部分重疊的綠色部分多受了個$-a$的影響,所以綠色部分$+a$消除影響。
最后$(x,y)$位置上的數值就是$c$數組在$(x,y)$位置的前綴和。