树状数组
对于序列a,我们设一个数组C
◦C[i] = a[i –2^k+ 1] + … + a[i]
◦k为i在二进制下末尾0的个数
◦2^k就是i 保留最右边的1,其余位全变0
◦i从1开始算!
C即为a的树状数组
2k=i &(i^(i-1)) 也就是i&(-i);
C[i] = a[i-lowbit(i)+1] + …+ a[i]C包含哪些项看上去没有规律
C1=A1
C2=A1+A2
C3=A3
C4=A1+A2+A3+A4
C5=A5
C6=A5+A6
C7=A7
C8=A1+A2+A3+A4+A5+A6+A7+A8
…………
C16=A1+A2+A3+A4+A5+A6+A7+A8+A9+A10+A11+A12+A13+A14+A15+A16
lowbit(x) 实际上就是x的二进制表示形式留下最右边的1,其他位都变成0ni-lowbit(ni) 是什么样子?就是ni的二进制去掉最右边的1。
如果a[i]更新了,那么以下的几项都需要更新:
C[n1], C[n2], …C[nm]
其中,n1 = i ,ni+1 = ni + lowbit(ni)
树状数组的好处在于能快速求任意区间的和a[i] + a[i+1] + … + a[j]
根据C的构成规律,可以发现sum(k)可以表示为:sum(k) = C[n1]+C[n2] + …+ C[nm]其中nm= k , ni-1 = ni-lowbit(ni);
所以有 C[k] = sum(k) –sum(k-lowbit(k))
所以,树状数组适合单个元素经常修改而且还反复要求部分的区间的和的情况。
如果每次要修改的不是单个元素,而是一个区间,那就不能用树状数组了(效率过低)。