樹狀陣列和線段樹聽說是區分acmer和其他人的重要區別,嘿嘿嘿。。。
樹狀陣列總體而言可以總結為乙個很簡單的問題複雜化,但是時間簡單化。
問題的引入:
給定n個數,a[1]…a[n]。每次我們可能有兩種操作:
(1)求出a[i]…a[j]的和;
(2)給a[x]的值加上乙個值val。
n的規模如果比較大(約100000)
該如何高效的實現?
這個時候如果我們通過暴力求解的話,1000ms的時間內如果資料達到了10e5就會直接超時,總體而言我們要找到一種新的方法進行工作,樹狀陣列應運而生。
這個太精彩了!!
方格中數字代表對應陣列的第幾個元素,下排是a陣列,其上方的是e陣列,最下的二進位制則是對應編號的二進位制表示.
箭頭表示這個陣列元素被哪個陣列元素包含了,比如e[2]=e[1]+a[2]=a[1]+a[2], e[4]=e[2]+e[3]+a[4]=e[2]+a[3]+a[4]=a[1]+a[2]+a[3]+a[4].
注意觀察:
1.a的每個元素至多僅被e的乙個元素包含,這點和樹有很大相同,但整體並不是樹
2.每個ei可認為是僅包含ai和其它若干個e元素
3.每個ei包含的元素數目(不包括ai在內)為i的二進位制表示中末位連續的0的個數
同時我們也會對於這個樹狀陣列的應用產生以下的疑問:
1.對應二進位制數的最末連續0的個數如何得知?
2.如何儲存?
3.如何在修改時訪問需要訪問的元素?
4.如何在求和時訪問需要訪問的元素?
就讓我們乙個乙個的來解決!
1、通過位運算進行解決
在實際應用中,我們需要的不是最末連續的0的個數,而是最末那段」1000」對應的十進位制數
lowbit(x) := (((x-1) xor x) and x);
或者:lowbit(x) := ((-x) and x);
2、儲存直接使用一維陣列就可以啦
如何訪問父親和兄弟?
由於某元素和其父親,最近的兄弟在下標上存在關係(與lowbit(x)有關),利用這個關係就可以用一維陣列儲存了,而且稍後你會發現,
儲存e陣列即可,無需儲存a陣列.
3、事實上修改操作只涉及到父節點的訪問
經過觀察和**,前人們得出了這個規律:
父親:比他大的,離他最近的,末位連續0比他多的數就是他的父親,x節點父親的編號=x+lowbit(x)
4、當我們求1…x的資訊時,e[x]如果包含的不是1…x的全部資訊,(比如e[6]=a[5]+a[6])就需要再找乙個ek累加起來,這個k我們稱之為x的前驅,舉個例子:
a[1]+a[2]+…+a[6]=e[6]+e[4],a[1]+a[2]+…a[7]=e[7]+e[6]+e[4]
前驅的編號即為比自己小的,最近的,最末連續0比自己多的數
所以前驅=x-lowbit(x)
當然這些都可以用我做的下面的**進行實現,為了方便理解,我通過迴圈把直接轉換為了**形式
#includeusing namespace std;
int lowbit(int x)
int change(int x)
return a;
}int getfather(int x)
int getson(int x)
int main()
return 0;
}
不方便編譯可以直接看我的答案:
1 二進位制:1 二進位制0的個數:1 他的父親節點:2他的前驅:0
2 二進位制:1 二進位制0的個數:2 他的父親節點:4他的前驅:0
3 二進位制:11 二進位制0的個數:1 他的父親節點:4他的前驅:2
4 二進位制:1 二進位制0的個數:4 他的父親節點:8他的前驅:0
5 二進位制:101 二進位制0的個數:1 他的父親節點:6他的前驅:4
6 二進位制:11 二進位制0的個數:2 他的父親節點:8他的前驅:4
7 二進位制:111 二進位制0的個數:1 他的父親節點:8他的前驅:6
8 二進位制:1 二進位制0的個數:8 他的父親節點:16他的前驅:0
9 二進位制:1001 二進位制0的個數:1 他的父親節點:10他的前驅:8
10 二進位制:101 二進位制0的個數:2 他的父親節點:12他的前驅:8
是不是很精彩呢~~ 樹狀陣列學習總結
樹狀陣列最大的特點就是求解特定區間的元素的和操作時間複雜度小o lgn 現對於傳統的順序求和的操作樹狀陣列在求解過程中採用了二進位制的思想,巧妙地化解了多次求和的重複操作,在很大程度上提高了效率。上圖是樹狀陣列的儲存於求解過程,給出的很詳細,陣列a存放的是原始的需要求和的元素,陣列c存放的是利用二進...
樹狀陣列總結
樹狀陣列的基本知識已經被各種大牛和菜鳥講到爛了,我就不多說了,下面給出基本操作的 假定原陣列為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...
樹狀陣列總結
樹狀陣列是對乙個陣列改變某個元素和求和比較實用的資料結構。兩中操作都是o logn 在解題過程中,我們有時需要維護乙個陣列的字首和s i a 1 a 2 a i 但是不難發現,如果我們修改了任意乙個a i s i s i 1 s n 都會發生變化。可以說,每次修改a i 後,調整字首和s在最壞情況下...