如果給定乙個陣列,要你求裡面所有數的和,一般都會想到累加。但是當那個陣列很大的時候,累加就顯得太耗時了,時間複雜度為o(n),並且採用累加的方法還有乙個侷限,那就是,當修改掉陣列中的元素後,仍然要你求陣列中某段元素的和,就顯得麻煩了。所以我們就要用到樹狀陣列,他的時間複雜度為o(lgn),相比之下就快得多。下面就講一下什麼是樹狀陣列:
一般講到樹狀陣列都會少不了下面這個圖:
下面來分析一下上面那個圖看能得出什麼規律:
據圖可知:c1=a1,c2=a1+a2,c3=a3,c4=a1+a2+a3+a4,c5=a5,c6=a5+a6,c7=a7,c8=a1+a2+a3+a4+a5+a6+a7+a8,c9=a9,c10=a9+a10,c11=a11........c16=a1+a2+a3+a4+a5+.......+a16。
分析上面的幾組式子可知,當 i 為奇數時,ci=ai ;當 i 為偶數時,就要看 i 的因子中最多有二的多少次冪,例如,6 的因子中有 2 的一次冪,等於 2 ,所以 c6=a5+a6(由六向前數兩個數的和),4 的因子中有 2 的兩次冪,等於 4 ,所以 c4=a1+a2+a3+a4(由四向前數四個數的和)。
(一)有公式:cn=a(n-a^k+1)+.........+an(其中 k 為 n 的二進位制表示中從右往左數的 0 的個數)。
那麼,如何求 a^k 呢?求法如下:
intlowbit(intx)
lowbit()的返回值就是 2^k 次方的值。
求出來 2^k 之後,陣列 c 的值就都出來了,接下來我們要求陣列中所有元素的和。
(二)求陣列的和的演算法如下:
(1)首先,令sum=0,轉向第二步;
(2)接下來判斷,如果 n>0 的話,就令sum=sum+cn轉向第三步,否則的話,終止演算法,返回 sum 的值;
(3)n=n - lowbit(n)(將n的二進位制表示的最後乙個零刪掉),回第二步。
**實現:
intsum(intn)
returnsum;
}(三)當陣列中的元素有變更時,樹狀陣列就發揮它的優勢了,演算法如下(修改為給某個節點 i 加上 x ):
(1)當 i<=n 時,執行下一步;否則的話,演算法結束;
(2)ci=ci+x ,i=i+lowbit(i)(在 i 的二進位制表示的最後加零),返回第一步。
**實現:
voidchange(inti,intx)
}樹狀陣列可以解決的題目型別:
1.單點更新,區間求值
2.區間更新,單點求值
3.逆序數(可以轉換為此類問題求解,poj2481)
4.順序數
5.求一組數中,第i個數前邊比a[i]大(小)的數之和或者後面比a[i]小(大)的數的和;例如hdu2492
6.求滿足a[i]a[k]>a[j]並且i>k>j等之類的問題(hdu2492)
樹狀陣列 演算法高階專題
lowbit i i i 或者i i i i 1 9 and 1 1 要點 乙個數i對應二進位制表示未尾0的個數為k,那麼他管轄的範圍為 從i到左邊i 2 k 1的2 k 個元素。如 i 6 110 k 1 6管轄的範圍為 c 5 a 5 a 6 2 1 管2個。2 求前n個元素的和,n的二進位制的...
樹狀陣列1 樹狀陣列入門
仔細看一下,發現tree的每乙個節點的高度並不是隨意的,而是由它轉成二進位制之後末尾連續零的數量決定的,連續零的數量加1,就是高度,例如 3 11 零的數量為0,加1等於1,所以它的高度就是1 6 110 零的數量為1,加1等於2,所以它的高度就是2 8 1000 零的數量為3,加1等於4,所以它的...
樹狀陣列總結
樹狀陣列的基本知識已經被各種大牛和菜鳥講到爛了,我就不多說了,下面給出基本操作的 假定原陣列為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...