無意間看到樹狀陣列,查了很多資料被各種圖和公式繞暈了,下面記錄一點個人理解。
假設陣列a[0],a[1],a[2],.....,a[n],記0-m元素之和為sum(m) (0=當我們頻繁的求s(m)時,第一種方法不適用,當我們頻繁的修改陣列a時,第二種方法每次都要修改陣列s,修改陣列s的時間複雜度為o(n)
而樹狀陣列可以很好解決這種場景,它類似方法二
方法二中我們定義s[m] = a[m]+a[m-1]+a[m-2]+....+a[0]
樹狀陣列中我們定義s[m]= a[m-1]+a[m-2]+....+a[i-2^k],其中k為m的二進位制的第乙個1前0的個數
ps:有些資料是m至i-2^k+1,那是陣列下標從1開始計數的,這裡下標從0開始,因此有所區別
舉個例子:10的二進位制1010,因此k=1;24的二進位制11000,因此k=3
我們記lowbit(m)=2^k,即有lowbit(10)=2,lowbit(24)=8
可以發現2的二進位制是10,8的二進位制是1000,因此lowbit的實現很簡單
static int lowbit (int x)
如果這方法無法理解,建議看下二進位制補碼
接下來陣列s就有的乙個公式
s[m]=a[m-1]+a[s-2]+....+a[i-lowbit(m)]
我覺得樹狀陣列講到這裡就可以了,為了便於理解,我舉乙個例子,測試**如下
public static void main(string args)
}public static string intbinarystring(int i)
public static string intfixedstring(int i)
列印結果
假設求sum(28),我們分析一下 i = 28 binary i = 00011100 lowbit = 4 i-2^k = 24
s[28]=a[27]+a[26]+....+a[24]
其中最後乙個數是24,繼續分析 i = 24 binary i = 00011000 lowbit = 8 i-2^k = 16
s[24]=a[23]+a[22]+....+a[16]
最後乙個數是16,繼續分析 i = 16 binary i = 00010000 lowbit = 16 i-2^k = 0
s[16]=a[15]+a[14]+....+a[0]
很容易發現sum(28)=a[28]+s[28]+s[24]+s[16],**實現如下
public int sum(int m)
return sum;
}
上面只是我的個人理解,如有錯誤,敬請指正。
參考:
樹狀陣列理解
c i 代表 子樹的葉子結點的權值之和 如圖可以知道 c 1 a 1 c 2 a 1 a 2 c 3 a 3 c 4 a 1 a 2 a 3 a 4 c 5 a 5 c 6 a 5 a 6 c 7 a 7 c 8 a 1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 再將其轉化為二進位製看...
樹狀陣列原理解析
我們知道,對長度為n的陣列,如果我們要改變其中某個值,則時間複雜度為o 1 如果要求出s m a 1 a 2 a m 則需要o m 的時間複雜度。若我們一邊修改陣列的值,一邊要求求出其部分和s m 使用一般的方法,時間複雜度是o m n 的,若m和查詢次數n很大,那麼該演算法將不可取。為了解決這個問...
深入理解樹狀陣列
先上模板 單點更新const int n 1003 int n int a n void update int i,int d intgetsum int i 區間更新const int n 1003 int n int a n void update int i,int d intgetsum i...