樹狀陣列詳解

2021-08-21 23:33:50 字數 1742 閱讀 6682

一、樹狀陣列是幹什麼的?

樹狀陣列或者二叉索引樹也稱作binary indexed tree,又叫做fenwick樹;它的查詢和修改的時間複雜度都是log(n),空間複雜度則為o(n),這是因為樹狀陣列通過將線性結構轉化成樹狀結構,從而進行跳躍式掃瞄。通常使用在高效的計算數列的字首和,區間和。

在圖中,a陣列就是原陣列,c陣列則是樹狀陣列,我們不難發現

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

為了發現這些公式的規律,我們要先了解lowbit(k)函式,它就是把k的二進位制的高位1全部清空,只留下最低位的1,例如10的二進位制是1010,則lowbit(k)=lowbit(1010)=0010(2進製),用**實現為:lowbit(k)=k&-k,這是位運算,我們知道乙個數加乙個負號是把這個數的二進位製取反+1,如-10的二進位制就是-1010=0101+1=0110,然後用1010&0110,答案就是0010了!

lowbit是用來聯絡a陣列和c陣列的!c[k]表示從a[k]開始往左連續求lowbit(k)個數的和,比如c[0110]=a[0110]+a[0101],就是從110開始計算了2(lowbit(0110)=0010)個數的和。可以看到其實只有低位的1起作用(lowbit(k)函式的作用)。可以顯然的得出c[0010]=a[0010]+a[0001],注意0010這個數,除了高位其餘位都是0,這時他本身本身就是lowbit,即k=lowbit(k)=k&-k。

既然關係建立好了,那麼如何實現a某乙個位置資料更改?其實a陣列不會直接改的,它每次更改其實都要通過維護c陣列的性質來實現的,通常後面的求和要用到。比如我們更改了a[0011],c3 = a3,c4 = a1+a2+a3+a4,c8 = a1+a2+a3+a4+a5+a6+a7+a8,從關係式中不難看出。c[0011],c0100],c[1000]會隨著a[0011]的改變而改變。(在程式中,資料的更改是由c陣列體現的,而c陣列的改變是由我們對c陣列進行操作來實現的)。c改變的係數與a的係數,它們之間有什麼必然聯絡或規律嗎?仔細觀察0011——>0100——>1000的變化,0011+0001=0100,1000=0100+0100,其滿足關係式

k=k+lowbit(k)。

不必考慮為什麼非要展開成這種關係, 我們只需注意:c的構成性質(分組性質):它決定了c[0011]只會直接影響c[0100];而c[0100]只會直接影響c[1000],單向影響的關係恰好滿足k +=lowbit(k),下面就是更新維護樹的**:

void add(int k,int num)

}

區間求和, 比如求a陣列0001~0110的和,c4 = a1+a2+a3+a4,c6 = a5+a6。就是c[0100]+c[0110]。

int read(int k)//1~k的區間和

return sum;

}

樹狀陣列是按照二分對陣列進行分組;維護和查詢都是o(lgn)的複雜度,複雜度取決於最壞的情況,也是o(lgn);lowbit這裡只是乙個技巧,關鍵在於明白c陣列的構成規律。

樹狀陣列 詳解

對於普通陣列,其修改的時間複雜度位o 1 而求陣列中某一段的數值和的時間複雜度為o n 因此對於n的值過大的情況,普通陣列的時間複雜度我們是接受不了的。在此,我們引入了樹狀陣列的資料結構,它能在o logn 內對陣列的值進行修改和查詢某一段數值的和。假設a陣列為儲存原來的值得陣列,c為樹狀陣列。我們...

樹狀陣列詳解

樹狀陣列求區間和的一些常見模型 樹狀陣列在區間求和問題上有大用,其三種複雜度都比線段樹要低很多 有關區間求和的問題主要有以下三個模型 以下設a 1.n 為乙個長為n的序列,初始值為全0 1 改點求段 型,即對於序列a有以下操作 修改操作 將a x 的值加上c 求和操作 求此時a l.r 的和。這是最...

樹狀陣列詳解

比如說,我這裡有一組數1,2,3,2,k。我想知道第i到第j的和 mathop sum limits j v i 是多少?樸素演算法 for int k 0 k n k if k i k j ans v k 類似這種的寫法,雖然在某些點值改變時也依然可以計算 我們稱這種問題為動態問題 但複雜度最高到...