树状数组

来源:互联网 发布:蜂窝数据没有app选项 编辑:程序博客网 时间:2024/06/06 01:11
树状数组是个很简单就能学会的东西,我以前学会了线段树就不想去学树状数组,今天无聊学习了一下,发现好简单,耗时不到1小时。
树状数组 - Marknoon - KeepItSimpleStupid
 如图为树状数组存储结构。
首先是用A数组读入所有的值,然后用C数组保存树状数组的值。
C[m]=sum(a[m-pow(2, k)+1],...a[m])=(m所管辖范围之和)。
我们看看上面这个公式,C数组所存的值就是其各自管辖区域的所有值和。
m-pow(2, k)+1就是管辖区域的第一个值,m就是最后一个。
那么管辖区域就是pow(2, k),k是m二进制末尾0的个数的值。
pow(2, k)可以用一个位运算求得:
int lowbit(int m)
{
return m & (m ^ (m - 1));
}
m^(m - 1)就会得到m二进制后缀0的个数k,其结果为k+1个1组成的二进制数。
然后再&m,其结果即为将k+1个1组成的二进制数的后k个1置0,也就是2的k次方。
接下来我们说说关于求和,对于区间1到m之间的和。
代码如下:
int sum(int m)
{
int s = 0;
while (m > 0)
{
s += c[m];
m -= lowbit(m);
}
return s;
}
对于上面代码,s每次都会加上当前m值所管辖范围的和,而每次相加后,m都要减去其管辖范围的大小。
要求区间4到7的和,那就是sum(7) - sum(3);
再接下来是修改区间的范围的值。
代码如下:
void update(int i, int x)
{
while (i <= n)
{
c[i] += x;
i += lowbit(i);
}
}
循环将区间里的每个 i 传入即可。


0 0
原创粉丝点击