树状数组学习笔记
来源:互联网 发布:怎么在知乎提问 编辑:程序博客网 时间:2024/06/06 08:58
理论
注意,这篇文章中,除解释了的,其它数字都表示都是二进制下的数字。
lowbit
- 对于二进制数 x,
lowbit(x)=2^k
,其中 k 为 x 末尾0
的个数。 - 即除掉”从右到左第一个
1
左边的数”,剩下的就是它的 lowbit 值。- lowbit(00000000)=0
- lowbit(00000001)=1
- lowbit(01110101)=1
- lowbit(00001010)=10
- lowbit(01010110)=10
- lowbit(01001000)=1000
- lowbit(10101000)=1000
要求 x 的 lowbit 值,可以利用二进制编码的特性。
lowbit(x)=x&(-x)
- 解释
- -x 为 x 的补码,等于
反码+1
; 反码
中,全部位取反,那么最后那一坨0
变成了1,而最右边那个1
变成了0;补码
是反码
再+1,则原来最右边为 1 的那一位会被进位成 1,右边又变回 0,左边的位都取反了。- 那么
原码
与补码
之后,只有 lowbit 值的只有原码最右边那个 1 的那位相同,得到的就是 lowbit 值了。 - 例子:
- 原码:
10101000
- 反码:
01010111
- 补码:
01011000
- 与值:
00001000
(即为lowbit值)
- 原码:
- -x 为 x 的补码,等于
c[]
- 对于数列
a[]
,建立树状数组c[]
。 c[x]=a[x-lowbit(x)+1]+...+a[x]
(从左边那个累加到右边那个)- c[100101]=a[100101]+…+a[100101]
- c[100100]=a[100001]+…+a[100100]
- c[100000]=a[000000]+…+a[100000]
- c[101100]=a[101001]+…+a[101100]
插入
- 若
a[x]
需要加y
,那么可以这么操作对树状数组(c[]
)做修改,n
为 a[] 的大小(元素个数)。
void plus(int x,int y){ while (x<=n){ c[x]+=y; x+=lowbit(x); }}
- 这应该是显然的,所有包含 a[x] 的 树状数组 中的节点都应该加上 y,而上面这个方法就能枚举出所有包含 a[x] 的节点。
- 因为包含 a[x] 的节点
c[k]
只需满足以下条件:lowbit值小于lowbit(x),且不小于x。- 例子
x=10110010
,则需修改的节点为以下10110010 (10110001~10110010)
10110100 (10110001~10110100)
10101000 (10100001~10101000)
10110000 (10100000~10110000)
11000000 (10000000~11000000)
- 例子
查询
- 一次查询本身只能求前缀,而可以通过前缀相减求得区间信息。
- 求前 x 个数的的和可以这样操作:
int query(int x){ int ret=0; while (x>0){ ret+=c[x]; x-=lowbit(x); } return ret;}
- 这个的正确性也可以自己举几个例子来理解:
- 例子
x=10100
a[1]+...+a[10100]
=c[10100] (10001~10100)
+c[10000] (00001~10000)
- 例子
- 后来我又想到一个说法,要是求前 x 个的和,可以把
1~x
看成一条线段 - 如图,灰色是原线段,那么将它“二进制化”(类似于十进制转二进制那样一位位除下来把它分成二的幂长度的若干段(每种长度最多出现一次)),每一段代表每一位,就成了个二进制数。
- 比如途中红色是绿色的四分之一,蓝色是红色的四分之一,要是蓝色长度为
10
,那么整一段的长度则可以表示为10101
(换成十进制的话就是22,你们可以算算,长度的确是蓝色的22倍) - 可以看出每一段对应着二进制表示中的一位
1
。 - 设左边为 0,那么每一段右端点代表的数的 c[] 值就是那一段元素的和。
- 每次累加当前
x
的c
值就是累加最右边那一段的元素,然后再x-=lowbit(x)
就是删去最右边那段。 - 这样以此次操作下来,每一段都被加了之后被删掉,轮到左边相邻那一段,最后加到的和就是整段
a[1]~a[x]
的和了。 - 不知道这样能不能理解。(有点倍增的味道)
参考文章(http://blog.csdn.net/howardemily/article/details/54974385),感觉还是很好的,帮助很大,建议看一看它,感觉比我的更全面,易懂。
阅读全文
0 0
- 树状数组学习笔记
- 树状数组学习笔记
- 学习笔记----树状数组
- 树状数组学习笔记
- 学习笔记:树状数组
- 树状数组学习笔记
- 树状数组学习笔记
- 树状数组学习笔记+poj2029
- 学习笔记 BIT(树状数组)
- 【学习笔记】树状数组求逆序对
- |算法讨论|树状数组 学习笔记
- 【树状数组】学习树状数组
- [笔记] 树状数组
- 树状数组拓展笔记
- 【数据结构】树状数组笔记
- [笔记]: 树状数组
- 【数据结构】树状数组笔记
- [树状数组] 笔记
- UVa 401 Palindromes
- 每天一道LeetCode-----回文链表
- 171019—循环语句实际操作
- 百度云搜索引擎网站
- 【安全牛学习笔记】python装饰器
- 树状数组学习笔记
- 循环队列的双循环链表结构
- 大数【加减乘除】算法
- 2017-10-19 远光软件Java开发面试+达达京东到家笔试总结
- 每天一个linux命令(12):more命令
- PHP预定义变量 PHP_EOL
- SVN与Git的区别
- Netfilter编程实现HTTP协议传输账号密码的抓取
- node.js学习笔记(一)