树形数组及应用

回顾/本期梗概

        上期我们学习了TrieAC自动树Trie空降链接),本期我们将学习树形数组及应用。


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对应的2进制为: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)树状数组求前缀和

//求数组[1,x]的所有数的和
int sum(int x){
    int rex=0;
    for(int i=x;i>0;i=i-lowbit(i))res+=c[x];
    return res;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值