前置知识
前缀和与差分
树状数组与线段树的整体关系
- 线段树更为的宏观(可以理解为线段树的作用效果包含树状数组)
- 树状数组的代码较短
树状数组的作用
- 以O(logn)的时间复杂度给某个位置上的数加上一个数(单点修改)
- 以O(logn)的时间复杂度求前缀和(区间查询)
树状数组可以快速、动态地求前缀和。
例如,有一个数组
将数组下标为4的位置加1,使其变为
同时,前四个数字的前缀和也由10变成了11
时间复杂度分析
对于一个长度为N的数组,如果修改了第一个元素的值,那么该点之后的前缀和都会发生变化,不利用树状数组修改,时间复杂度为O(n),大于树状数组的O(logn)
树状数组的构造(证明略)
- 树状数组的下标从1开始
- 树状数组是一个一维的数组
- 设原数组为A,树状数组为C,若下标x为奇数,则
C[x] = A[x]
- 如何确定层数?对于C[x],若x的二进制末尾有k个0,则C[x]在第k层
- 如何确定范围?C[x]等于左开右闭区间(x - 2^k,x]中所有数的和
lowbit(x) = x & -x
:对于一个数x,如果其二进制的末尾有k个0,则返回2^k- 综上,C[x]等于左开右闭区间
(x - lowbit(x),x]
中所有数的和
不难发现:
C[1] = A[1]
C[2] = A[1] + A[2]
C[3] = A[3]
C[4] = A[1] + A[2] + A[3] + A[4]
C[5] = A[5]
C[6] = A[5] + A[6]
C[7] = A[7]
C[8] = A[1] + A[2] + A[3] + A[4] + A[5] + A[6] + A[7] + A[8]
C[9] = A[9]
C[10] = A[9] + A[10]
C[11] = A[11]
C[12] = A[9] + A[10] + A[11] + A[12]
C[13] = A[13]
C[14] = A[13] + A[14]
C[15] = A[15]
C[16] = A[1] + A[2] + A[3] + A[4] + A[5] + A[6] + A[7] + A[8]
+A[9] + A[10] + A[11] + A[12] + A[13] + A[14] + A[15] + A[16]
… …
根据以上信息,可以画出如下的树状数组