樹狀陣列 講解

2022-05-05 21:30:08 字數 2864 閱讀 1927

樹狀陣列(binary indexed tree(b.i.t))

是乙個查詢和修改複雜度都為log(n)的資料結構。主要用於查詢任意兩位之間的所有元素之和,但是每次只能修改乙個元素的值;經過簡單修改可以在log(n)的複雜度下進行範圍修改,但是這時只

請看下圖:

我們令每個葉節點代表每乙個元素。

現在我們變形一下,順便加上陣列的編號:

a陣列是原資料。

b陣列的節點,代表其所有子節點之和。

b[1] = a[1]

b[2] = a[1] + a[2]

b[3] = a[3]

b[4] = a[1] + a[2] + a[3] + a[4] 

b[5] = a[5]

b[6] = a[5] + a[6]

b[7] = a[7]

b[8] = a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] 

這時,我們再把b陣列轉化成二進位制編碼:

可以發現:

1=(001)      b[1] = a[1]

2=(010)      b[2] = a[1] + a[2]

3=(011)      b[3] = a[3]

4=(100)      b[4] = a[1] + a[2] + a[3] + a[4]

5=(101)      b[5] = a[5]

6=(110)      b[6] = a[5] + a[6]

7=(111)      b[7] = a[7]

8=(1000)    b[8] = a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] 

對照式子可以發現b[i] = a[i-2^k+1] + a[i-2^k+2] + ......a[i](k為i的二進位制中從最低位到高位連續零的長度)例如i=8時,k=3,i=7時,k=0,i=2時,k=1。

由此我們引出了lowbit函式:

lowbit(i) = 2^k

b[i] = a[i-lowbit(i)+1] + a[i-lowbit(i)

+2] + ......a[i]

1

int lowbit(intx)2

其實......很短......背吧......

接著是修改函式:

1 void add(int k, int

num)

28 }

bit就是b陣列在位置k上加上num,我們用lowbit列舉出與k有關的位置,依次加上num。

舉個栗子:

比如我們要修改1位置的值。與之有關的是b[1] b[2] b[4] b[8]。

第一次 k = 1,bit[1] += num後,lowbit(1) = 1,k+=1;

第二次 k = 2,bit[2] += num後,lowbit(2) = 2,k+=2;

第三次 k = 4,bit[4] += num後,lowbit(4) = 4,k+=4;

第四次 k = 8,bit[8] += num後,lowbit(8) = 8;

another:

修改3位置的值。與之有關的是b[3] b[4] b[8]。

第一次 k = 3,bit[3] += num後,lowbit(3) = 1,k+=1;

第二次 k = 4,bit[4] += num後,lowbit(4) = 4,k+=4;

第三次 k = 8,bit[8] +=num後, lowbit(8) = 8;

最後是查詢操作:

在這裡,我們反著來做

1

int query(intk)2

9return

sum;

10 }

跟修改的原理是一樣的,不過是反著做,比如查詢7位置之前所有的和,就是bit[7] + bit[6] + bit[4]。

這裡你會想,我們的查詢函式是查詢從 1——k 的值的和,要是查詢乙個區間 l——r(包含 l 和 r 的值) 的話怎麼辦?

我們利用字首和的思想,查詢 l——r 就等於query(r) - query(l-1)。

所以,luogu p3374 樹狀陣列的模板1,就解決啦~

1 #include2 #include3 #include4

using

namespace

std;

5int

n,m;

6int bit[500070],a[500070];7

int lowbit(intx)8

11void add(int k, int

num)

1218}19

int query(int

k)20

27return

sum;28}

29int

main()

3037

38for(int i=1;i<=m;i++)

3948

else

49if(c == 2

) 5055}

56return0;

57 }

樹狀陣列 講解

樹狀陣列 插點法 插線法 最常見的一種用途是求乙個數列的前n項和 比如說陣列a 吧 把他轉化一下存入樹狀陣列c 中 如 c 1 a 1 c 2 a 1 a 2 c 3 a 3 c 4 a 1 a 2 a 3 a 4 c 16 a 1 a 2 a 16 也即c n 管理著2 k個數 k代表二進位制n最...

樹狀陣列(講解 模版)

樹狀陣列 如果給定乙個陣列,要你求裡面所有數的和,一般都會想到累加。但是當那個陣列很大的時候,累加就顯得太耗時了,時間複雜度為o n 並且採用累加的方法還有乙個侷限,那就是,當修改掉陣列中的元素後,仍然要你求陣列中某段元素的和,就顯得麻煩了。所以我們就要用到樹狀陣列,他的時間複雜度為o lgn 相比...

樹狀陣列入門 簡單的原理講解

樹狀陣列可以解決什麼樣的問題 這裡通過乙個簡單的題目展開介紹,先輸入乙個長度為n的陣列,然後我們有如下兩種操作 輸入乙個數m,輸出陣列中下標1 m的字首和 對某個指定下標的數進行值的修改 多次執行上述兩種操作 尋常方法 對於乙個的陣列,如果需要求1 m的字首和我們可以將其從下標1開始對m個數進行求和...