树状数组及应用

1. 什么是树状数组

        树状数组是一个查询和修改复杂度都为 log( n ) 的数据结构。主要用于:数组的单点修改、区间求和。

        在使用前缀和求区间和的算法中,如果可以做到在 O( 1 ) 的时间复杂度内查询任意的区间和,但是如果要修改其中一个点的值,那么需要修改一遍前缀和数组,修改的时间复杂度是O(n)。

(1)树状数组拆分原理

        正如所有的整数都可以表示成 2 的幂和,我们也可以把一串序列子序列的和。采用这个想法,我们可以将一个前缀和划分成多个子序列的和,而划分的方法与数的 2 的幂和具有极其相似的方式。

        比如:整数 21 的对应的 2 进制是 10101,对应运算 = 2^{4}+2^{2}+2^{1},因此一个长度为 21 的数组,可以拆分为三段:

        子序列的个数是其二进制表示中 1 的个数。

        根据该理论,一个长度为 len 的区间 [ 1,len ],可以采用上述思想划分 log( len ) 个子区间。

        从右往左看,每个区间的大小其实是 len 对应的二进制的最后一个 1 的 2 的次幂。

 (2)如何求整数 x 对应的最后一个 1 往后的值?

        lowbit( x ) :代表 x 对应 2 进制的从最后一位 1 开始向后构成的值。

        例如:

        lowbit( 10 ):返回 10.

        lowbit( 40 ):返回 1000.

        计算方法:

        假设 x = 270 对应的二进制为:1011,1000.

        先将 x 取反 = 0100,0111,再+1 = 0100,1000,此时发现这个值和原来的 x 对应的 2 进制,最后一个 1 向后的值一致,前面的值正好相反,只要那这两个值做 & 运算,结果就是 lowbit( x )  的值。

        在计算机中,负数是以补码的形式存储的,补码就是数值位取反+1的过程。

        因此:lowbit( x )  = x & ( ~x + 1 ) = x & -x;

(3)树状数组的划分方法

        以 a[ x ] 结尾的区间,区间的长度为 x 的最后一个 1 所对应的 2 的次幂。

        A. 以 a[ x ] 结尾的区间,区间长度为 x 的最后一个 1 所对应的 2 的次幂。

        B. 设定 c[ x ] 表示:a 数组中 ,长度为 lowbit( x ) 的区间和,所管理的区间为[ x - lowbit( x ) +1,x]。

        C.该结构的特点:

                a、除树根外,结点 x 的父节点 = x + lowbit( x );

                b、长度为 n 的数组 a,所构建的树的深度 = log( n );

        注意:树状数组的下标一般从 1 开始,因为如果从 0 开始,lowbit( 0 ) = 0,容易出现死循环。

(4)树状数组修改元素

//在数组 a 的第 x 数上增加数字 k
void update(int x,int k){
    for(int i=x;i<=n;i=i+lowbit(i)) c[x]+=k;
}

 (5)树状数组求前缀和

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值