標籤:1.5 一個 分享圖片 擴充 進一步 時間 注意 color 深度
樹狀數組
樹狀數組的修改和求和都是O(logn),效率非常高。
樹狀數組——lowbit(x)例如21二進位是10101,1所在的位置是0,2,4,可以分解成2^4 + 2 ^ 2 + ^ 0。進一步的[1,x]可以分解成O(logx)個小區間:
1.長度為2^4的小區間[1,2^4]
2.長度為2^2的小區間[2^4 + 1,2^4+2^2]
3.長度為2^0的小區間[2^4+2^2+1,2^4+2^2+2^0]
樹狀數組
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[6] + A[5];
C[7] = A[7];
C[8]=A[1] + A[2]+A[3] + A[4]+A[5] + A[6]+A[7] + A[8]
樹狀數組滿足以下性質:
1.每個內部結點C[x]儲存以它為根的子樹所有分葉節點。
2.每個內部結點C[x]的子結點個數等於lowbit(x)的大小。
3.除樹根外,每個內部結點c[x]的父結點是c[x + lowbit(x)]
4.樹的深度為O(logn)。
一、求lowbit(n)
lowbit(n)就是非負整數n在二進位表示下最低位的1以及它後邊的0構成的數值。
{補碼錶達式~n = -1-n }因此lowbit(n) = n&(~n+1) = n&(-n)。
1 int lowbit(n)2 {3 return n&(-n);4 }
二、對某個元素進行加法操作
任意一個結點的祖先至多隻有logN個,我們逐一對他們的數組C值進行更新即可。下面的代碼在O(logN)時間內執行單點增加操作。
1 void update(int x,int y)2 {3 for(i = 1;i <= N;x += x & (-x))4 {5 c[x] = c[x] + y;6 }7 }
三、查詢首碼和
如本篇開頭所寫,分成O(logn)個數組,每個數組的區間和都已儲存在數組C中,下面的代碼在O(logn)的時間內查詢首碼和。
1 int sum(int x) 2 { 3 int ans = 0; 4 while(x > 0) 5 { 6 ans = ans + c[x]; 7 x = x - (x & (-x)); 8 return ans; 9 }10 }
四、統計A[x]……A[y]的值。
調用以上的sum的操作:sum(y) - sum(x - 1)
五、擴充(多維樹狀數組)
複雜度變成O(logn)^m
有一個N*M的二維數組,樹狀數組是c,那麼單點修改操作為:
1 int update(int x,int y,int z)//將(x,y)的值加上z 2 { 3 int i= x; 4 while(i <= n) 5 { 6 int j = y; 7 while(j <= m) 8 { 9 c[i][j] += z;10 j += lowbit(j); 11 } 12 i += lowbit(i);13 } 14 }
1 int sum(int x,int y) 2 { 3 int res = 0,i = x; 4 while(i > 0) 5 { 6 int j = y; 7 while(j > 0) 8 { 9 res = res + c[i][j];10 j -= lowbit(j);11 }12 i -= lowbit(i);13 }14 return res;15 }
六、注意事項
樹狀數組的下標不能是0,否則lowbit(0) = 0 ,會陷入死迴圈中。
樹狀數組