樹狀陣列總結

2021-06-18 14:49:50 字數 2060 閱讀 3774

樹狀陣列是對乙個陣列改變某個元素和求和比較實用的資料結構。兩中操作都是o(logn)。

在解題過程中,我們有時需要維護乙個陣列的字首和s[i]=a[1]+a[2]+...+a[i]。

但是不難發現,如果我們修改了任意乙個a[i],s[i]、s[i+1]...s[n]都會發生變化。

可以說,每次修改a[i]後,調整字首和s在最壞情況下會需要o(n)的時間。當n非常大時,程式會執行得非常緩慢。

因此,這裡我們引入「樹狀陣列」,它的修改與求和都是o(logn)的,效率非常高。

【理論】

為了對樹狀陣列有個形象的認識,我們先看下面這張圖。

如圖所示,紅色矩形表示的陣列c就是樹狀陣列。

這裡,c[i]表示a[i-2^k+1]到a[i]的和,而k則是i在二進位制時末尾0的個數,或者說是i用2的冪方和表示時的最小指數。

( 當然,利用位運算,我們可以直接計算出2^k=i&(i^(i-1)) )

同時,我們也不難發現,這個k就是該節點在樹中的高度,因而這個樹的高度不會超過logn。

所以,當我們修改a[i]的值時,可以從c[i]往根節點一路上溯,調整這條路上的所有c即可,

這個操作的複雜度在最壞情況下就是樹的高度即o(logn)。  

另外,對於求數列的前n項和,只需找到n以前的所有最大子樹,把其根節點的c加起來即可。

不難發現,這些子樹的數目是n在二進位制時1的個數,或者說是把n展開成2的冪方和時的項數,因此,求和操作的複雜度也是o(logn)。

樹狀陣列中用的c,每個點都有一定的管轄範圍;

如c[1]=a[1];             1->0001 最後一位1代表的數字為1,所以是從a[1]向前(包括a[1])共乙個數字的和

c[2]=a[1]+a[2];        2->0010 最後一位1代表的數字為2,所以是從a[2]向前共兩個數字的和

c[3]=a[3];

c[4]=a[1]+a[2]+a[3]+a[4];

等等;接著,我們考察這兩種操作下標變化的規律:

首先看修改操作:

已知下標i,求其父節點的下標。

我們可以考慮對樹從邏輯上轉化:

如圖,我們將子樹向右對稱翻摺,虛擬出一些空白結點(圖中白色),將原樹轉化成完全二叉樹。

有圖可知,對於節點i,其父節點的下標與翻摺出的空白節點下標相同。

因而父節點下標 p=i+2^k  (2^k是i用2的冪方和展開式中的最小冪,即i為根節點子樹的規模)

即  p = i + i&(i^(i-1)) 。

接著對於求和操作:

因為每棵子樹覆蓋的範圍都是2的冪,所以我們要求子樹i的前一棵樹,只需讓i減去2的最小冪即可。

即  p = i - i&(i^(i-1)) 。

至此,我們已經比較詳細的分析了樹狀陣列的複雜度和原理。

在最後,我們將給出一些樹狀陣列的實現**,希望讀者能夠仔細體會其中的細節。

【**】

求最小冪2^k:

int lowbit(int t) 

這個函式主要是用來求的是某個點管轄範圍;

如果是 t+=lowbit(t) 就是得到的該點的父節點的值;比如t=4時;就能得到8;

而 t-=lowbit(t)  的話,就是得到t這個點的管轄區間的下個區間的管轄點;

比如說,t=7,代入後6;不斷迴圈到0能依次得到 6.。。4.;

他們所有的管轄區間正好是1....7;

求前n項和:

int sum(int end) 

return sum; } 

這個函式就是求區間和了。。比如sum(7)的話,就是求a[1]+a[2]+...a[7];求乙個一般區間的和如 sum( 4,9)可以化成 sum(9)- sum(3)來做。

對某個元素進行加法操作: 

void plus(int pos , int num)  

} 這個函式,是用來修改樹狀陣列的;

如果是一般的演算法只用修改改點就可;但是樹狀陣列必須修改所有改點被管轄的區間;

比如把a陣列的 a[2]減去1,(令n=16);則所有2被管轄的點有4,8,16都應該減去1;

就是呼叫函式 update(2,-1);

資料來自

樹狀陣列總結

樹狀陣列的基本知識已經被各種大牛和菜鳥講到爛了,我就不多說了,下面給出基本操作的 假定原陣列為a 1.n 樹狀陣列b 1.n 考慮靈活性的需要,使用int a傳陣列。define lowbit x x x int sum int a,int x void update int a,int x,int...

樹狀陣列總結

今天學習了一下樹狀陣列,做乙個簡單總結。樹狀陣列可分為兩種操作,1 修改單個點,統計區間和 一般為 向上修改 update1 向下統計 sum1 2 修改區間,統計單個點 一般為向下修改 update2 向上統計 sum2 主要模板如下 int c n int lowbit int x 用於確定區間...

樹狀陣列總結

樹狀陣列適合單個元素經常修改而且還反覆要求部分的區間的和的情況。樹狀陣列的所有題線段樹都可以寫,但相對而言程式設計效率和程式執行效率更加高 c只是乙個求和工具 每個c i 最後乙個元素都是a i c i 中有lowbit i 個元素,所以c i 就是 a i lowbit i 1 a i 的和 c的...