树状数组(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 }