树状数组(Binary Indexed Tree)

Posted wushengyang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组(Binary Indexed Tree)相关的知识,希望对你有一定的参考价值。

对于学习的线段树方面的,发现很多问题可以用它来求解,但是做题的时候发现,用线段树太容易tle也,很多次也是卡时间过的,然后就发现了树状数组。

首先我们搞明白树状数组是用来干嘛的,树状数组是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值,经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。

所以说,树状数组的求解和线段树的求解有些重合,但是功能没有线段树的那么广泛。但是对树状数组来说,其思想大概是用二进制的方法来实现。

先简单介绍下基本二进制的使用方法:

& 按位与       如果两个相应的二进制位都为1,则该位的结果值为1,否则为0
| 按位或        两个相应的二进制位中只要有一个为1,该位的结果值为1
^ 按位异或    若参加运算的两个二进制位值相同则为0,否则为1
~ 取反           ~是一元运算符,用来对一个二进制数按位取反,即将0变1,将1变0
<< 左移         用来将一个数的各二进制位全部左移N位,右补0  (<<1则是乘2)
>> 右移         将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数,高位补0(>>1则是除2)

原理:lowbit      

 lowbit这个函数的功能就是求某一个数的二进制表示中最低的一位1,举个例子,x = 6,它的二进制为110,那么lowbit(x)就返回2,因为最后一位1表示2

那么怎么求lowbit呢?把这个数的二进制写出来,然后从右向左找到第一个1(这个1就是我们要求的结果,但是现在表示不出来,后来的操作就是让这个1能表示出来),这个1不要动和这个1右边的二进制不变,左边的二进制依次取反,这样就求出的一个数的补码,说这个方法主要是让我们理解一个负数的补码在二进制上的特征,然后我们把这个负数对应的正数与该负数与运算一下,由于这个1的左边的二进制与正数的原码对应的部分是相反的,所以相与一定都为0,;由于这个1和这个1右边的二进制都是不变的,因此,相与后还是原来的样子,故,这样搞出来的结果就是lowbit(x)的结果。

然后后面的看到大佬的博客就直接贴个博客链接了,感觉大佬讲解的很详细了。

贴个大佬的模板:

 

int lowbit(int x){
    return x & -x;
} 

void update(int i,int val){   //单点更新 
    while(i<=n){
        c[i]+=val;
        i+=lowbit(i);   //由叶子节点向上更新树状数组c,从左往右更新 
    }
}

int sum(int i){    // 求区间[1,i]内所有元素的和 
    int ret=0;
    while(i>0){
        ret+=c[i];  //从右往左累加求和
        i-=lowbit(i); 
    }
    return ret;
}

 

原文博客链接:https://www.cnblogs.com/acgoto/p/8583952.html

 

以上是关于树状数组(Binary Indexed Tree)的主要内容,如果未能解决你的问题,请参考以下文章

树状数组(Binary Indexed Tree)

树状数组(Binary Indexed Tree)

树状数组(Binary Indexed Tree,BIT)

Fenwick Tree / Binary Indexed Tree (树状数组)的学习

LeetCode线段树 segment-tree(共9题)+ 树状数组 binary-indexed-tree(共5题)

高级数据结构之Fenwick Tree(Binary Indexed Tree)