##概述算法
樹狀數組是在研究壓縮算法時被發現,可以高效的解決RMQ問題,能將樸素方式解決RMQ問題的O(n)的時間開銷下降爲O(lgn)。數組
##特色ui
查詢和更改都爲O(lgn),code
其思想與線段樹類似ip
空間開銷爲O(n),比線段樹小,但不能解決區間最值問題.get
##原理it
觀察上圖能夠獲得以下規律:原理
C1 = A1 C2 = A1 + A2 C3 = A3 C4 = A1 + A2 + A3 + A4 C5 = A5 C6 = A5 + A6 C7 = A7 C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 ... C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16
因而能夠總結出,給定序列(數列)A,咱們設一個數組C知足:im
C[i] = A[i–2^k+ 1] + … + A[i] (k爲i中末尾0的個數)總結
則咱們稱C爲樹狀數組.
給定i,如何求2^k?
答案很簡單:
2^k=i&(i^(i-1)) = i&(-i)
因而能夠用C語言以下實現該功能:
int lowbit(int x) { return x&(-x); }
###求和
如圖,由於C[i] = a[0] + a[1] + ..a[i],因此i~j的和爲 C[j] - c[i - 1],所以將求區間和問題轉化爲求前K項和。
int sum (int k) { int ans = 0; for (int i = k; i > 0; i -= lowbit(i)) ans += BIT[i]; return ans; }
###構建
定義一個數組 BIT,用以維護A的前綴和,則:
具體能用如下方式實現:(C++)
void build() { for (int i=1;i<=MAX_N;i++){ BIT[i]=A[i]; for (int j=i-1; j>i-lowbit(i);j-=lowbit(j)) BIT[i]+=BIT[j]; } }
###更改
根據圖示,能夠看出更新實際是從被變動的葉子開始回溯至根節點變沿途更新記錄的過程.
void edit(int i, int delta) { for (int j = i; j <= MAX_N; j += lowbit(j)) BIT[j] += delta; }
##參考文章