树状数组

树状数组

概念

树状数组是用来解决单点修改,区间查询的问题,它的修改与求和都是\(O(log_2n)\)的,效率非常高。它与前缀和的区别是能够修改数组中的元素。

基本思想

根据任意正整数关于\(2\)的不重复次幂的唯一分解性质,若一个正整数\(x\)的二进制表示为\(10101\),则\(x\)能够被分解为\(2^4+2^2+2^0\)。将\(x\)转化为有\(x\)个元素的区间\([1,x]\),则区间\([1,x]\)可以被分解为\(log_2x\)个小区间:

  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]\)

树状数组就是一个基于以上思想的数据结构,其将\([1,x]\)拆分为\(log_2x\)个小区间,从而快速求得前缀和。

算法实现

由上述思想可知:若区间结尾为\(x\),则区间长度就等于\(x\)的二进制表示中,最右侧的\(1\)与它右边的\(0\)构成的数字(分解后最小的\(2\)次幂),我们设求\(x\)的最小二次幂为\(lowbit(x)\)

对于给定的序列\(A\),我们建立一个数组\(sum\),其中\(sum[x]\)保存序列\(A\)的区间\([x-lowbit(x)+1,x]\)中的所有数的和。

\(lowbit(x)\)的求法:

\(lowbit(x)=x \& (\) ~ \(x+1)\)

先把\(x\)取反,此时\(k\)位为\(0\)\(k\)为最末一位\(1\)),\(0\)\(k\)位都为\(1\),再让\(x+1\)。此时因为进位,\(k\)位为\(1\)\(0\)\(k\)位都为\(0\)。与原数位与运算后,\(k\)后面的数位都因为取反而得出\(0\),此时只有\(k\)位是\(1\)

因为计算机补码为\((\) ~ \(n+1)\),得出答案\(lowbit(x)=x\&(-x)\)

扩展应用

  1. 多维前缀和(与一维类似),时间复杂度为\(O(log^m_2n)\)

注意

树状数组下标不能为\(0\),否则\(lowbit(0)=0\),陷入死循环。

posted @ 2025-03-10 22:48  nightmare_lhh  阅读(11)  评论(0)    收藏  举报