树状数组的功能: 区间查询 单点修改 O(logn)
举个例子
16个数的数组 eg:
8 6 1 4 5 5 1 1 3 2 1 4 9 0 7 4
两两合并求和 以便查询
14 5 10 2 5 5 9 11
再合并
19 12 10 20
31 30
61
一直计算只剩一个元素为止
例如计算前15个只需计算4个即可
再观察 有些数字是根本不会被用到的 会重复算
例如5计算前两个和前三个时用不上 计算前四个和前五个直接用19即可
结论 每一层的第偶数个数都可以去掉
观察剩下的数据 恰好还剩个n个 即为树状数组
先认识一下 lowbit函数 求出二进制位最低位代表哪一个数字
int lowbit(int x)
{
return x&(-1);
}
观察树状数组发现 第一行数据区间长度为2 ....每一层区间长度即为 lowbit(i)
*序号为i的序列正好是长度为lowbit(i)并且以i结尾的序列*
还有一个性质 序列b[i]正上方的的序列正好就是b[i+lowbit(i)] 即其父节点
所以我们在修改某一个值时只需要不断加上lowbit(i) 就可以找到上方的所有序列进行修改
为啥修改是对的?修改为啥只需要改其父节点呢?
因为子节点对应唯一的父节点 只能影响到唯一的父节点
第x个数加上k
void add(int x, int k)
{
for(int i = x; i <= n; i += lowbit(i))
t[i] += k;
}
查询前x个数的和
查询这个点的前缀和,需要从这个点向左上找到上一个结点,将加上其结点的值
int ask(int x)
{
int sum = 0;
for(int i = x; i; i -= lowbit(i))
sum += t[i];
return sum;
}