樹狀陣列 小白

2021-10-16 04:26:33 字數 2552 閱讀 9879

樹狀陣列(bit)是一種利用樹的2進製特徵進行檢索的樹狀結構。樹狀結構是一種奇妙的資料結構,不僅非常高效,而且**十分簡潔(比線段樹的**要短且更易理解,但是可以解決的問題也是有限的,沒有線段樹那麼廣泛)

樹狀陣列就是用來 動態的求字首和·(**的時間複雜度在log n之內)

一般來說就是兩個操作 :1.單點修改 2.區間查詢(通俗來說就是給某個位置上的數加上乙個數;求字首和)

當然平時做題的時候也不止這兩種操作 比如有1.區間修改 2.單點查詢 或者 1.區間修改 2.區間查詢

(這幾種操作本質上還是用樹狀陣列解決 只不過是需要用到差分 將它轉化為最初的兩個操作)

下面開始舉乙個例子

長度為n的數列

,進行以下操作。

(1) 修改元素add

(k,x)

;把ak

(ak為數列中第k個數)加上x;

(2)求和sum

(x):x<=n,sum=a1+a2...

..+ax;

那麼區間和ai+..

...+aj=

sum(j)

-sum

(i-1

).

這個程式很好寫,用迴圈加或者字首和,複雜度是o(n).但是,如果n很大的話,這樣做的效率會非常低。所以我們需要掌握樹狀陣列。

先看**:

int

lowbit

(int x)

void

add(

int x,

int v)

intsum

(int x)

add()和sum()的複雜度都是o(log2 n).(打不出來這個東西 ?)

在理解上述**的之前 先看***這張圖

這張圖就是解釋了add()構建tree陣列 tree[1]=a[1] tree[2] =a[1] +a[2]; tree[3] =a[3] tree[4] =a[1]+a[2]+a[3] … 連線就代表此時tree[x]的值為那些連線位置的和

可是為什麼是這些值呢

這就要看這個神奇的操作了 lowbit(x) .lowbit(x)=x&-x,功能是找到x的二進位制的最後乙個1.其原理是利用負數的補碼表示,補碼是原碼取反加一。例如x=6=00000110,-x=x補=11111010,

那麼lowbit(x) =x&-x=10(2進製)=2;

仔細觀察就會發現 讓補碼與原碼一一對應 以x的2進製的最後乙個1為中心 原碼和補碼左邊的部分是剛好相反的 所以在對x&-x操作時 前面的部分都為0 0&0 當然也為0 所以x&-x=10(2進製的)=2;

是不是很妙

lowbit(x)有什麼用呢?

在求和計算和tree陣列的更新都可以通過lowbit()完成。

借助tree陣列求sum,例如:

sum[8] =tree[8];

sum[7]=tree[7]+tree[6]+tree[4];

sum[9]=tree[9] +tree[8];

那如何得到上面的關係呢

對tree的查詢可以通過lowbit(x)實現。例如sum[7]=tree[7]+tree[6]+tree[4];

首先從7開始,加上tree[7] ;

然後7 - lowbit(7)(值為1) =6 再加上tree[6] ;

然後6 - lowbit(6)(值為2) =4 再加上tree[4]

最後4 - lowbit(4) (值為4) =0,結束;

關於tree[ ]陣列的更新

當你改變a[x]的值 加個3 tree陣列的值也應當變化 這個也使用了lowbit(x)

例如 當你改變a[6]的值後

對於tree陣列來說肯定是6以後的位置收到影響 所以

tree[6] +=3; 然後 6 +lowbit(6) =8;

tree[8] +=3; 然後8 +=lowbit(8) =16;

以此類推 直到tree[n];

所以add() 也是用的這種方法 來初始化tree陣列

for(int i;i<=n ;i ++) add

(i,a[i]);

這樣就是對tree[

]陣列進行初始化

*這裡需要注意一下樹狀陣列的下標起始一定是從1開始 如果題目下標有0的話 可以進行加1處理

說了這麼多 應該都懂了樹狀陣列了吧

接下來就開始 實戰演練了 幫助你鞏固 加強理解

這是樹狀陣列的一道模板題 直接套就可以了(

然後關於樹狀陣列較難的題 我也還在學習中? 以後遇到會加進去的

那就先這樣吧 本人小白 如有錯誤歡迎各位大佬指正

//南昌理工學院acm集訓隊

小白初理解樹狀陣列

樹狀陣列,是乙個查詢和修改複雜度都為log n 的資料結構。主要用於查詢任意兩位之間的所有元素之和,但是每次只能修改乙個元素的值 經過簡單修改可以在log n 的複雜度下進行範圍修改,但是這時只能查詢其中乙個元素的值。可以用一張圖來弄懂什麼是陣列陣列。原陣列a n 樹狀陣列c n 如果n為奇數 cn...

樹狀陣列 小白篇(1)

身為一名弱省oier中的mengbier,簡單講一下我是怎麼學會基礎的樹狀陣列的 不算華麗的分割線 主要用於查詢任意一段資料中的所有元素之和。經過簡單修改可以在log n 的複雜度下進行範圍修改。也就是說你通過一系列神奇的操作可以實現在乙個數列中,修改其中一項ax的值 還可以是一段 並求出前n項和 ...

樹狀陣列 小白演算法學習

在解題過程中,我們有時需要維護乙個陣列的字首和s i a 1 a 2 a i 但是不難發現,如果我們修改了任意乙個a i s i s i 1 s n 都會發生變化。可以說,每次修改a i 後,調整字首和s在最壞情況下會需要o n 的時間。當n非常大時,程式會執行得非常緩慢。因此,這裡我們引入 樹狀陣...