树状数组(BIT)

  • OI Wiki
  • 《算法笔记》

前言

利用大节点来存储小节点的信息。在查询或修改的时候直接利用大节点的信息,节省时间。

事实上,树状数组的代码要比线段树短得多,思维也更清晰,在解决一些单点修改的问题时,树状数组是不二之选

lowbit运算

形式一

l o w b i t ( x ) = 2 m a x { ⁡ i │ x m o d    2 i = 0 } lowbit(x) = 2^{max \{⁡{i│x\mod 2^i=0\} }} lowbit(x)=2max{ixmod2i=0}

能整除x的最大2的幂次

形式二

l o w b i t ( x ) = x & ( − x ) lowbit(x) = x \&(-x) lowbit(x)=x&(x)

补码储存方式: − x -x x相当于把 x x x二进制每一位取反,再+1,等价于把 x x x二进制最右边1的左边的每一位都取反

那么KaTeX parse error: Expected '}', got '&' at position 9: x\text{ &̲ }(-x)就是x二进制最右边的1和右边的0。

image-20210126111309956

树状数组

基本知识

image-20210126112236745

假设我们大小节点之间的关系是求和。对于原数组 a,我们用新的树状数组 t 来辅助。

t i = a i , i = 1 , 3 , 5 , 7 t_i=a_i, i=1,3,5,7 ti=ai,i=1,3,5,7

t 2 = a 1 + a 2 , t 6 = a 5 + a 6 t_2=a_1+a_2, t_6=a_5+a_6 t2=a1+a2,t6=a5+a6

t 4 = a 1 + a 2 + a 3 + a 4 t_4=a_1+a_2+a_3+a_4 t4=a1+a2+a3+a4

t 8 = ∑ i = 1 8 a i t_8=\sum^8_{i=1} a_i t8=i=18ai

如果要查 a 1 → a 5 a_1→a_5 a1a5的和,如果树状数组存储的是和,直接用 t 5 + t 4 t_5+t_4 t5+t4 即可。查 a 1 → a 7 a_1→a_7 a1a7 的和,直接 t 7 + t 6 + t 4 t_7+t_6+t_4 t7+t6+t4 即可

那么我们主要要解决两个问题:

  • 怎么知道某个点由哪几个点组成?
  • 怎么修改和查询?

怎么知道某个点由哪几个点组成

对于编号为 x x x的某点,由 l o w b i t ( x ) lowbit(x) lowbit(x)个点组成

  • t [ 6 ] t[6] t[6]为例, l o w b i t ( 6 ) = 2 lowbit(6) = 2 lowbit(6)=2,有两个点组成

    因为 6 ( 10 ) = 11 0 ( 2 ) 6_{(10)} = 110_{(2)} 6(10)=110(2),按照lowbit定义 11 0 ( 2 ) 110_{(2)} 110(2)最右边的1和右边的0为 1 0 ( 2 ) 10_{(2)} 10(2),对应十进制为2。

int lowbit(int x) {
  return x & -x;
}

单点修改+单点查询

复杂度 O ( l o g ⁡ n ) O(log⁡n) O(logn)

单点修改:修改一个元素 x 后对哪些数产生了影响?可以由图直观得出产生影响的范围是 x 通过不断加 lowbit(x) 能得到的值。

// 单点修改(第x个整数加v)
void update(int x, int v) {
  for(int i = x; i<= n; i += lowbit(i))
      a[i] += v;
}

单点查询:每次让 x 减去 lowbit(x)

// 单点查询
int getsum(int x) {  // a[1]……a[x]的和
  int sum = 0;
  for(int i = x; i> 0; i -= lowbit(i)){	// 注意是>0
      sum += a[i];	
  }
  return sum;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值