樹狀數組(binary indexed tree)
概念:是一種數組結構
目的:高效地獲取數組中連續n個數的和。
應用 :序列中的元素可不斷地被修改,要快速地獲取某區間和(單點更新,區間求和)
前注 :如果每次要修改的不是單個元素,而是一個區間,那不應當用樹狀數組(效率過低)
操作:
1.修改元素(增減值) –> O(logn)
2.求區間和 –> O(logn)
實現:
給定序列(數列)A,我們設一個數組C滿足
C[i] = A[i–2^k+ 1] + … + A[i]
(K爲 i在二進制下末尾0的個數, i >= 1) --> 給定 i,則有 2^k = i&(i^(i-1)) = i&(-i)
圖示:
修改元素:
————–>若要修改A[i]的值時,只需從C[i]往根節點一路上溯,調整這條路上的所有C[]。
區間求和:
————–>求數列的前n項和,只需找到n以前的所有最大子樹,把其根節點的C[]值加起來。(子樹的數目是n在二進制時1的個數)
int lowbit(int n)
{//求 2^k , k 爲n在二進制下末尾0的個數
return n & (-n); // == n & (n^(n-1));
}
int Sum(int End)
{//求前n項和
int ans = 0;
while(End > 0)
{
ans += treeC[End];
End -= lowbit(End);
}
return ans;
}
void Plus(int pos,int num,int len)
{//增加某元素的值
while( pos <= len )
{
treeC[pos] += num;
pos += lowbit(pos);
}
}
例題 http://acm.hdu.edu.cn/showproblem.php?pid=1166
高級應用 : 區間更新 單點查找
操作:
1.區間更新
例如 :
在 區間[ Begin,End] 加 Add
則Plus(Begin,Add) Plus(End+1,-Add)
實現了更新區間[ Begin,End] 的值而不改變其他值
2.單點查找
Sum(i) 即爲 A[i] 的值
例題 http://acm.hdu.edu.cn/showproblem.php?pid=1556
推廣 : 二維樹狀數組
用途 :
一個由數字構成的大矩陣,能進行
操作
1) 修改矩陣元素(增減值)
2) 求子矩陣的和
求和有
有 C[x][y] = sum{ A[i][j] , x - lowbit[x] +1 <=i <= x , y-lowbit[y]+1 <= j <=y }