树状数组
简介¶
树状数组和下面的线段树可是亲兄弟了,但他俩毕竟还有一些区别:
树状数组能有的操作,线段树一定有;
线段树有的操作,树状数组不一定有。
这么看来选择线段树不就 「得天下了」 ?
事实上,树状数组的代码要比线段树短得多,思维也更清晰,在解决一些单点修改的问题时,树状数组是不二之选。
原理¶
如果要具体了解树状数组的工作原理,请看下面这张图:
最下面的八个方块就代表存入
他们上面的参差不齐的剩下的方块就代表
很显然看出:
所以,如果你要算区间和的话,比如说要算
那么这种类似于跳一跳的连续跳到中心点而分值不断变大的原理是一样的(倍增)。
你从
用法及操作¶
那么问题来了,你是怎么知道 lowbit
:
1 2 3 4 | int lowbit(int x) { //算出x二进制的从右往左出现第一个1以及这个1之后的那些0组成数的二进制对应的十进制的数 return x & -x; } |
lowbit
的意思注释说明了,咱们就用这个说法来证明一下
发现第一个
这就是 lowbit
的用处,仅此而已(但也相当有用)。
你可能又问了:x & -x 是什么意思啊?
代表 -x 的负数,计算机中负数使用对应的正数的补码来表示。 x
例如 :
神奇吧,我也觉得神奇!
那么对于 单点修改 就更轻松了:
1 2 3 4 5 6 7 | void change(int x, int k) { while (x <= n) //不能越界 { c[x] = c[x] + k; x = x + lowbit(x); } } |
每次只要在他的上级那里更新就行,自己就可以不用管了。
1 2 3 4 5 6 7 8 9 | int getsum(int x) // a[1]……a[x]的和 { int ans = 0; while (x >= 1) { ans = ans + c[x]; x = x - lowbit(x); } return ans; } |
区间和 也不用说了吧,代码十分清真。
例题¶
build本页面最近更新:,更新历史
edit发现错误?想一起完善? 在 GitHub 上编辑此页!
people本页面贡献者:
copyright本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用