树状数组(Binary Indexed Tree/Fenwick Tree)笔记

假定原始数组为x[i], 树状数组为BIT[i].

1. 求任意前缀和,单点更新的时间复杂度为O(lgn) (n为数组大小)

2. 树状数组第i个元素BIT[i]保存了2^L 个数组x元素的和.L为 i的二进制表达式里从右数第一个1的位置(位置从0开始).比如如果 i的二进制为10000100,那么L = 2, BIT[i]的值等于2^2=4个x数组元素的值.

并且是从 x[[i]开始到往前数2^L个x数组的元素之和:

BIT[i]=\sum_{k=i-2^L-1}^{i}x[k]

下面是索引从1到16的BIT数组元素对应的x数组元素和映射表:

                                               

从上面的图可以看出,x数组的任何一个元素在BIT数组里出现的次数都是新数组大小对数级的.

3.单点更新

假如x[5]的值变了,我们需要更新 BIT[5], BIT[6],BIT[8], 和 BIT[16]; 5加1(5的二进制右数第一个1的位置为0, 2^0 = 1)等于6;6加上2(6的二进制右数第一个1的位置为1, 2^1 = 2)等于8;

8加上8(8的二进制右数第一个1的位置为 3, 2^3 =8)等于16.这样就遍历了所有需要更新的树状数组.

我们定义一个函数 lowestOneBit(int i),它返回值是 2^L, L为输入的二进制右数第一个1的位置.

int lowestOneBit(int i)
{
    return i & ( -i );
}

这个实现利用了补码的思想(负数的补码等于原码取反加1).

另一种实现:

int lowestOneBit( int i )
{
    return i - i & ( i - 1 );
}

那么,单点更新的函数实现如下:

void update( int index, int delta )
{
    int i;
    for( i = index; i < ARRAY_SIZE; ++i)
    {
        BIT[i] += delta;
        i += lowestOneBit(i);
    }
}

4. 区间求和:

求 x数组1到i的和(前缀和):

int getRangedValue(int end )
{
    int ret = 0;
    int i = end;
    while( i > 0 )
    {
        ret += BIT[i];
        i = i - lowestOneBit(i);
    }
    return ret;
}

如果是求任意区间的和,可以求两次前缀和,然后相减得到.

参考:

http://www.cs.ucf.edu/~dmarino/progcontests/cop4516/notes/BIT-Notes.pdf

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值