樹狀陣列(binary indexed tree(b.i.t), fenwick tree)是乙個查詢和修改複雜度都為log(n)的資料結構。主要用於查詢任意兩位之間的所有元素之和,但是每次只能修改乙個元素的值;經過簡單修改可以在log(n)的複雜度下進行範圍修改,但是這時只能查詢其中乙個元素的值(如果加入多個輔助陣列則可以實現區間修改與區間查詢)。
個人拙見:其實呢,是一種長的像樹的可以高效查詢子陣列的和以及可以修改元素的陣列。
首先呢,a是乙個陣列,如果叫你求a的任意子陣列的和,有個聰明的辦法就是在讀入a的資料時,建立陣列b,b[i]是從a[0]到a[i]的和,然後呢,求子陣列的和時就可以利用b陣列的兩個元素相減求得子陣列的和, 就目前為止,該辦法沒什麼毛病,可是呢,問題很快來了,如果a的元素會被修改呢,那陣列b就要隨之改變啊,如果a[i]改變,則b[i]以後的所有元素都要改變。那麼樹狀陣列可以避免去改變陣列b嗎,答案是no,那為什麼還用樹狀陣列呢,因為他依然要改變b,但它改變的項會遠遠小於前面的做法。
說到現在,才開始進入正題,如果我們依舊沿著前面的思路,創造乙個陣列c,但在這裡c[i]不在是a[0]到a[i]的和了
看一下上面的圖,
如果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
...好好,看到這裡有同學估計和我一樣脾氣上來了,什麼狗屁玩意啊,ci到底等於什麼啊,每乙個ci等於幾個a元素的和,可是這幾個a[i]的數目和ci到底有什麼關係呢。
穩定一下軍心,首先ci中的i寫成二進位制形式,比如c4吧,4寫成二進位制100,末尾有兩個0,所以呢,等號右邊有2^2個數,即c4管轄這a中的a1,a2,a3,a4這四個數,c4是他們的和。再比如c7,寫成二進位制111,末尾有零個0,所以等號右邊有2^0=1個數,即c7管轄著a中的a7著乙個數,c7是他們的和。那有人問了,我程式中還要這麼麻煩啊,先求二進位制,然後數末尾的0,你有毒吧。其實呢,有個現成的東西,
int
lowbit(
int
x)
lowbit 返回的就是x在二進位制下末尾的0的個數。
那如何每次更新c[i]呢,比如說吧,輸入或者更新了a1吧,收先c1肯定要變吧,即a1+k或者a1-k的話,c中所有含有a1的項都要+k或者-k吧,那麼從上面的式子來看,c2,c4,c8都也要變,可是用程式怎麼寫呢,好,更新a1加k,令i=1,ci+k,然後呢,i=i+lowbit(i),看看i是不是等於2,ci+k,然後繼續下去i=i+lowbit(i),看看是不是i=4.
用**實現
voidupdate(intx,intv)
其中x是表示ax發生變化,v表示ax發生的變化。
那麼如何求sum[i]呢(sum[i]表示a[0]到a[i]的和)
比如sum[7]=(a[7])+(a[6]+a[5])+(a1 + a2 + a3 + a4)=c7+c6+c4
規律跟上面差不多,反過來的,sum[i]=ci+sum[i-lowbit(i)];
用**實現
intgetsum(intx)
以上就是本菜鳥的所以拙見了,希望大家多多包含。
關於樹狀陣列
身為蒟蒻的我 終於學會了 樹狀陣列 但因為自己還是太蒟蒻 還是糊里糊塗的 所以寫個部落格理理思路 樹狀陣列的數學模型 樹狀陣列的劃分依據的原理是任何正整數都可以表示為2的冪相加的形式 如13 2 3 2 2 2 1 進而可以利用這一特性來進行區間求和 設想一下現在乙個序列 長度為n 現在要進行區間求...
關於樹狀陣列
樹狀陣列的核心在於對一段區間的修改和查詢,巧妙地把陣列用一顆樹表示,從而降低了對陣列的修改和查詢的複雜度。首先引入lowbit int lowbit x 如 x 1 1 0000 0001 1111 1111 1 x 6 6 6 0000 0110 1111 1010 2 總結一下就是 求出某個數二...
關於樹狀陣列的幾點總結
零 樹狀陣列的基本概念 1.概念 2.實現原理 3.特性 1.概念 這是樹狀陣列最基本的應用,也就是支援單點修改區間查詢 時間複雜度均為 2.實現原理 3.具體實現 不停獲取i的二進位制表示中的最後一位1所代表的值 將這個值設為b 在操作過程中 在迴圈中給i增加b之前 向c陣列中下標為i的地方增加x...