字首和 & 差分

xggx發表於2024-07-16

字首和

一維字首和

一維字首和主要用於計算任意區間的元素和。

計算字首和

sum[i] =  sum[i - 1] + a[i];

計算區間[l, r]的元素和

s = sum[r] - sum[l - 1];  

二維字首和

二維字首和是一種用於快速計算二維陣列中任意子矩陣元素之和。
字首和 & 差分

// 計算矩陣的字首和
s[x][y] = s[x - 1][y] + s[x][y - 1] - s[x - 1][y - 1] + a[x][y]
// 計運算元矩陣的和
sum = s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]

主要計算公式有以上兩種,計算矩陣的字首和即計算左圖中所有有顏色區域,其中s[x - 1][y]是紅加綠色區域,s[x][y - 1]是黃加綠色區域;計運算元矩陣的和即計算右圖中藍紫色區域。

差分

一維差分

一維差分是與一維字首和緊密相關,它主要用於對陣列進行區間更新操作,如需要對某個區間內的所有元素進行相同的增加或減少操作。
假設原陣列為 \(a\), 差分陣列為 \(b\)

  • 構造差分陣列

\(b[1] = a[1]\)
\(b[2] = a[2] - a[1]\)
……
\(b[i] = a[i] - a[i - 1]\)
……
\(b[n] = a[n] - a[n - 1]\)

  • 區間更新操作
// 對區間 [l, r] 進行加 c
b[l] =+ c;
b[r + 1] -= c;
  • 陣列恢復
    在對差分陣列 \(b\) 進行了一系列區間更新操作後,透過計算字首和來恢復原陣列 \(a\),即 \(a[i] = a[i − 1] + b[i]\)

二維差分

二維差分,類似於一維差分,是一個二維陣列的子矩陣進行統一的增加或減少操作。
字首和 & 差分
假設原陣列為 \(a\), 差分陣列為 \(b\)
對上圖中的綠色區域加c。

void insert(int x1, int y1, int x2, int y2, int c)
{
    b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;
}

insert(i, j, i, j, a[i][j]);      // 記得構建差分陣列

insert(x1, y1, x2, y2, c);        // 差分陣列加c

恢復原陣列操作與二維字首和類似

a[i][j] = b[i][j] + a[i − 1][j] + a[i][j − 1] − a[i − 1][j − 1]
//or 直接用b陣列儲存
b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1]

相關文章