身為一名弱省oier中的mengbier,簡單講一下我是怎麼學會基礎的樹狀陣列的
不算華麗的分割線
主要用於查詢任意一段資料中的所有元素之和。
經過簡單修改可以在log(n)的複雜度下進行範圍修改。
也就是說你通過一系列神奇的操作可以實現在乙個數列中,修改其中一項ax的值(還可以是一段),並求出前n項和(也可以是任意一段)。
額妹子!!!對不對?
我們知道 「樹狀陣列」 這個名詞的定語是 「樹狀」 ,它只是用來修飾陣列的對不對?
所以 「樹狀陣列」 就是一串有特異功能的陣列!
舉個例子:
正常的乙個陣列:a[1]=1, a[2]=2, a[3]=3, a[4]=4, a[5]=5, a[6]=6 ,a[7]=7, a[8]=8, a[9]=9
你要得到第n個數,就直接用a[n]來表示吧(廢話)
但你要算前x項和的話,就只能從a[1]一項一項加到a[x], 顯然當需要大量計算時,這種方法非常耗時!!!
於是機智的你想到了先計算出每乙個sn來,但是當需要修改怎麼辦?
難道要每乙個有關的sn都修改嗎?
於是大佬們yy出了樹狀陣列
神奇的陣列: c[1]=1, c[2]=3, c[3]=3, c[4]=10, c[5]=5, c[6]=11, c[7]=7, c[8]=36, c[9]=9
我說裡能表達所有資訊,你信不信?
神出鬼沒的分界線
設節點編號為x,那麼這個節點管轄的區間為2^k(其中k為x二進位制末尾0的個數)個元素。這個區間最後乙個元素為ax,
所以很明顯:cn = a(n – 2^k + 1) + ... + an
也就是說例如:
c[1], 1的二進位制數為1,k=0,它就管長度為2^0的區間的和,暨c[1]=a[1]
c[2], 2的二進位制數為10,k=1,它就管長度為2^1的區間的和,暨c[2]=a[1]+a[2]
c[4], 4的二進位制數為100,k=2,它就管長度為2^2的區間的和,暨c[4]=a[1]+a[2]+a[3]+a[4]
c[6], 6的二進位制數為110,k=1,它就管長度為2^1的區間的和,暨c[6]=a[5]+a[6]
c[9], 9的二進位制數為1001,k=0,它就管長度為2^0的區間的和,暨c[9]=a[9]
強烈建議讀者用紙筆模擬一遍!!!
有乙個函式可以簡單的計算出這個2^k
1int lowbit(intx)2
不信就用筆算一算
那我現在要求前n項和怎麼辦?
那就從c[n]開始,不重複的加完資料!
例如:我要求前6項和,那就從c[6]開始加,發現c[6]已經代表了2項,加完c[6],就加c[6-2],加c[4]的值,發現c[4]代表了4項,此時就加完前6項
還是看**吧
1int sum(intn)2
910return
ans;
11 }
那要改一項的值就要改中每個有關的項
1void add(int x,int v) //
x位置加v
28 }
那從a[x]+a[x+1]+a[x+2]+……+a[y-1]+a[y],就可以表示為sum(y)-sum(x-1);
就是任意連續數列和了
神出鬼沒的分界線
在下的文字功底還是不行,可能講的不是很好,請見諒
提供一些有關樹狀陣列的題目:
新手練習1
新手練習2(需要抽象化模型)
樹狀陣列 小白
樹狀陣列 bit 是一種利用樹的2進製特徵進行檢索的樹狀結構。樹狀結構是一種奇妙的資料結構,不僅非常高效,而且 十分簡潔 比線段樹的 要短且更易理解,但是可以解決的問題也是有限的,沒有線段樹那麼廣泛 樹狀陣列就是用來 動態的求字首和 的時間複雜度在log n之內 一般來說就是兩個操作 1.單點修改 ...
樹狀陣列 小白篇(2)暨區間修改
這篇主要來講一講樹狀陣列的區間修改 因為乙個乙個點改,毫無疑問耗時太長 所以,機智的人類yy出了用差分來表示陣列 為了便於理解,簡單一點陣列 a 1 0,a 2 0,a 3 0,a 4 0,a 5 0,a 6 0 a 7 0,a 8 0,a 9 0 用差分思想,delta x 表示a x a x 1...
樹狀陣列1 樹狀陣列入門
仔細看一下,發現tree的每乙個節點的高度並不是隨意的,而是由它轉成二進位制之後末尾連續零的數量決定的,連續零的數量加1,就是高度,例如 3 11 零的數量為0,加1等於1,所以它的高度就是1 6 110 零的數量為1,加1等於2,所以它的高度就是2 8 1000 零的數量為3,加1等於4,所以它的...