前綴和與差分


前綴和
其實可以把它理解為數學上的數列的前n項和(對於一個一維數組的前綴和)。

我們定義對於一個數組$a[]$的前綴和數組$s$,$s[i] = a[1]+a[2]+...+a[i]$.

二維前綴和與一維前綴和類似,設$s[i][j]$表示所有$a[i{}'][j{}']$的和。$(1\leq i{}'\leq i,1\leq j{}'\leq j)$
有一點像“矩形的面積”那樣,把一整塊區域的值都加起來。

前綴和的用途

一般用來求區間和
對於一維情況
現在給出一個數列$a$,要求回答$m$次詢問,每次詢問下標$l$到$r$的和

朴素的做法顯然是對於每次詢問都執行一次相加操作,然后輸出結果。這樣做是正確的,但是當$m$過大時就會導致計算次數過多而有可能超時。
超時的原因一目了然,重復計算。那么我們應該怎么改進這個方法呢?

想象一下,我們如果先提前算好了每一個位置的前綴和,然后用$s[r]-s[l-1]$,結果不就是我們這次詢問的答案嗎?這樣便會使計算量大大減小。

對於二維的區間和,也是類似的

 
我們借助這個圖片研究一下。假設在這個矩陣(二維數組)中,我們要求和的是上圖中紅色區域。現在我們已經預處理出了所有點的前綴和,現在給定兩個點$(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,有$q$個操作,每次操作給定$l,r,x$表示$[l,r]$區間所有的數都加上$x$。並求修改后的序列$a$。
暴力做法顯然會$TLE$,我們考慮用差分的做法。

之所以叫做差分,是因為我們需要維護的數據是“相鄰兩個數之差”。

差分數組不僅僅是一個優秀的數據結構,還是一種很好的思想

差分數組的功能是修改區間,查詢點。修改區間的時間復雜度是$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)$位置的前綴和。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM