树状数组
引入
lowbit的求解
介绍
给定包含 个数的数组 。有两种操作:
查询区间 数的和。把 增加 。
分析
与线段树的区别与联系
我们知道线段树的区间是按照中间点划分的,而树状数组是根据 来划分区间的。线段树的一个结点的区间是通过递归参数计算的,而树状数组的一个结点表示的区间可以根据结点标号计算出来,对于结点 ,其表示的区间为 ,然后我们再用一个数组 表示每个结点对应的区间内的数的和。
下图为15个节点的树状数组:
灰色的结点是树状数组中的结点,每一层结点的 相同。而每个灰色结点 和其后面的白色长条就代表了结点 表示的区间。
查询
若要查询区间 的和值,我们可以先求出 的和值,然后减去 的和值。现在问题就是怎么求 上的和值。实际上很简单
令 。
加上区间 的和值。
然后令 。
如果 则退出,否则重复步骤 。
等价于将 的二进制的最后一个 减去。而 的二进制里最多有 个 ,所以查询效率是 的。
例如查询 的和。

代码为:
int getsum(int x) {
int res = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
res += C[i];
}
return res;
}更新
如果让 增加 ,那么只有对于包含位置 的区间的和值才会受到影响。而求出哪些区间受影响有一个巧妙的操作,就是一直令 ,直到 ,这一过程中所有的 都是受影响的点。
如下图对应更新点 。

void update(int x, int v) {
for (int i = x; i <= n; i += lowbit(i)) {
C[i] += v;
}
}这一步的复杂度也是 。
性质
为什么树状数组只用来求区间和值?
因为树状数组只能求出区间 的信息,用来求区间和只是通过前缀和转换了一下,所以如果是求区间最大(最小)值,就只能求区间 到 了,因为最大(最小)不满足加减的性质。
树状数组的比较方便,代码量小,并且常数较小。
数组数组能解决的问题是线段树的子集,线段树能解决树状数组不能解决的问题。
树状数组为什么没有建树,因为初始的时候,依次更新 个元素代替了建树。当然线段树也可以这么做。