基本思想
根据任意正整数都可以被关于2的不重复次幂的唯一分解性质,若一个正整数x被分为10101,其中等于1的位是0,2,4,所以x可以被分解为2^4 + 2 ^ 2 + 2 ^ 0,进一步,区间为[1, x]的序列可以分成log(x)个小区间:
1 长度为2 ^ 4的[1, 2 ^ 4];
2长度为2 ^ 2的[2 ^ 4 + 1, 2 ^4 + 2 ^ 2];
3长度为2 ^ 0的[2 ^4 + 2 ^ 2 + 1, 2 ^4 + 2 ^ 2 + 2 ^ 0];
树状数组就是一种基于上述思想的一种数据结构,基本用途就是维护前缀和,将x长的序列分成log(x)个区间,更快
基本算法
由上文可知,若区间结尾为r, 那么区间的长度为r在二进制拆分下最小的2的正整数次幂,我们设为lowbit(r).
对于给定的一个序列a,我们设一个数组c,c[x]保存a的序列[x - lowbit(x) + 1, x]中的所有数的和
下图为树状数组的树形结构
该结构满足以下性质::
1 每个节点c[x]保存以他为根的所有子树的所有叶节点的和
2每个节点c[x]的长度为lowbit(x)
3除了树根,每个节点c[x]的父节点就是c[x + lowbit(x)]
4树的深度为log(x)
求lowbit
lowbit(n)表示的是n在二进制下最低的1以及他后面的0构成的数值,那么怎么求呢???
我们来看,一个数的二进制位10001100, 我们可以用他来按位与100,这样我们就可以得到了
首先,我们把它取反,此时数就变成了01110011, 我们将他加1,变成了01110100,这样我们就会发现,我们将n&100 == n&01110100,是不是就可以了?
所以为n&(~n + 1),可不可以在简单一下???
当然可以 在二进制补码下~n = -1 -n,将他带入我们就得到了-n,所以lowbit(x) = x & -x
对某个元素进行加法操作
树状数组支持单点操作,对于单点加法,我们维护的是前缀和,所以我们只要将x及x以后的c数组加上y就可以了!
代码如下:
查询前缀和
树状数组支持查询前缀和,即序列A第1~x数的和。
自己理解吧,时间复杂度为O(logN),代码如下:
统计x-y的值为:sum(y) - sum(x - 1)
拓展
区间修改 区间和查询
代码