树状数组算法详解·目录
树状数组的引入
相信读者一定知道什么是前缀和,形如一串数 a 1 , a 2... , a n , s u m [ i ] = a [ 1 ] + a [ 2 ] + . . . + a [ i ] a1,a2...,an,sum[i]=a[1]+a[2]+...+a[i] a1,a2...,an,sum[i]=a[1]+a[2]+...+a[i]
前缀和在算法的优化上占有很重要的地位,一般就会预先对数据进行预处理运算以后,再在运算过程中用 O ( 1 ) O(1) O(1)时间调用,这样的操作很大程度上避免了实际运算中的枚举,NOIP2016魔法阵就是一个典型的例题。
But前缀和也有其缺陷:
当原序列中的数据修改后如果快速调用前缀和??
在此,我们引入了一个名叫树状数组的算法,快速将单点修改和区间查询优化到 O ( l o g n ) O(logn) O(logn)级别。
lowbit的含义
l o w b i t ( i ) lowbit(i) lowbit(i)表示非负整数i再二进制下最低位1以及末尾0的个数。
例如,二进制 1001001100 1001001100 1001001100中, 100 100 100的长度为 3 3 3,所以这个数字 l o w b i t lowbit lowbit运算的结果为 3 3 3。
根据计算机(dev-c++)的运算法则可得,lowbit(i)=i&-i .
树状数组的前缀和存储方式
对于每一个求和数组 c [ i ] , c [ i ] c[i],c[i] c[i],c[i]的求和范围 a [ i − l o w b i t ( i ) + 1 ] a[i-lowbit(i)+1] a[i−lowbit(i)+1]~ a [ i ] a[i] a[i].
用一幅图可以形象直观的解释其存储方式:
单点修改
对于 a d d ( x , v a l ) add(x,val)