火速上手树状数组
树状数组的代码非常简单,但原理十分复杂,还涉及到一些不算容易的前置知识。这里总结出树状数组的用法与代码,旨在帮助初学者快速上手树状数组这一强大的数据结构。
lowbit
lowbit(x)
指一个整数x去掉二进制表示下所有高位的1之后剩下的数。
比如,10(十)的二进制表示是1010
,lowbit(10)
就是0010
,即lowbit(10) = 2
。
lowbit(x)
的代码如下。
1 | int lowbit(int x) |
后续的代码都需要用到这里的lowbit
。
树状数组区间查询
树状数组能快速回答任意区间的和的询问,时间复杂度。用树状数组本身能得到的的只是前缀和,求区间的的值需要用两个前缀和做差(当然,如果你不理解什么是前缀和也没有关系,会写代码就好了)。
1 | int sum(int x, int *bit) //求x处的前缀和 |
树状数组单点修改
在树状数组上修改一个点的值的时间复杂度是,代码如下
1 | void point_add(int num, int x, int *bit) //将序列的第num个元素加上x |
上面的这个函数实现的功能是将序列的第num个元素加上x。如果是想“把序列的第num个元素变成x”,就相当于
“将序列的第num个元素加上x-a”,其中a为该元素本来的值。
树状数组不能直接访问到一个元素的值,所以不能直接得到上面的所说的a。因此如果需要“把序列的第num个元素变成x”需要先调用之前的区间查询函数得到a,再“将序列的第num个元素加上x-a”
1 | void turn(int num, int x, int *bit) //将第i个元素的值变成x |
树状数组区间修改
两个树状数组联动可以通过4次单点修改实现区间修改。这其中用到了差分的思想。
1 | //将闭区间[l,r]上所有元素加上x |
由于变成了两个树状数组联动,如果需要使用区间修改功能的话,之前的单点修改就不能直接用了,也需要用这个函数来进行单点修改(使区间左端点等于右端点)。同时,之前的查询也不能用了,需要用到下面这个函数
1 | //求闭区间[l,r]所有元素的和 |
使用例:POJ3468,区间修改模板题
1 |
|