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