树状数组

时间复杂度

树状数组是一个查询和修改的时间复杂度都为 l o g ( n ) log(n) log(n)的数据结构。一般来说树状数组能解的题目,线段树都能解,但是线段树能解的问题,树状数组不一定能解。但是树状数组的有点在于方便实现,代码量少。

树状数组的结构

在这里插入图片描述

图中的A数组是原来的数组,C数组就是树状数组,如果先将A数组的每个元素都先放在C数组中,则:
C数组中每一位所存的信息都由前面的某些位的信息构成,以求A的前缀和为例
C 1 C_1 C1中存放的和就是 C 1 C_1 C1
C 2 C_2 C2中存放的和是 C 1 + C 2 C_1+C_2 C1+C2
C 3 C_3 C3中存放的和就是 C 3 C_3 C3
C 4 C_4 C4中存放的和就是 C 2 + C 3 + C 4 C_2+C_3+C_4 C2+C3+C4

如何去寻找树状数组中每一位所对应的其他位

假设当前位是i,现在要将i位置的和加到i后面的某些位上。
树状数组每个位置的下标其实是以二进制来对应的,例如:

1d=1b
2d=10b=1b+1b
3d=11b
4d=100b=11b+1b=10b+10b

即将i写成2进制,并从右往左找,找到第一个1,并用i加上这个1所对应的的权值,就是i后面的第一个要找的位。
那么如何高效的寻找上述的1成为这个数据结构的关键。
对任意的一个数i(二进制是xxxx1...),它的相反数-i(二进制是XXXX1...
上面表达式二进制中的xxxx取反是XXXX...表示不定数量的0
那么求从右往左的第一个1所对应的的权值那就是 i & ( − i ) i\&(-i) i&(i),一般用lowbit(i)表示这个值

如何构建和更新树状数组

对树状数组而言,构建和更新其实是一样的操作:

  • 先将A数组中的每一个数都放在C数组的 1 1 1~ N N N
  • 然后对C数组中的每一个元素将其下标i不断地加上lowbit(i),直到大于 N N N为止,这样一个树状数组就构建完成

如何查询前缀和

查询A数组中下标为i的前缀和

  • 先定义一个sum存放和
  • sum不断地累加 C i C_i Ci,且每次累加后令 i − = l o w b i t ( i ) i-=lowbit(i) i=lowbit(i),直到i<1为止

练手题:如何用树状数组求数组中的中位数

### 树状数组的数据结构实现及应用 #### 什么是树状数组树状数组(Binary Indexed Tree, BIT)是一种基于数的二进制特性的高效数据结构,用于支持动态数上的区间查询和单点/区间更新操作。它通过一种特殊的形结构来存储累积信息,从而能够在对数时间内完成这些操作[^1]。 #### 树状数组的核心特性 树状数组的主要特点在于其编程简单性和高效的性能表现。相比于其他复杂的数据结构(如线段),树状数组仅需少量代码即可实现核心功能,并且运行速度更快[^3]。 #### 基本操作原理 树状数组的操作依赖于 `lowbit` 技术,该技术能够提取整数最低位的1及其后续零所表示的数值。具体而言: - **Lowbit函数定义**:对于任意正整数 \( x \),\( lowbit(x) = x \& (-x) \)[^4]。 此函数帮助定位父节点以及子节点之间的关系,在构建和维护树状数组时起到关键作用。 #### 查询与更新方法 以下是树状数组两种基本操作的具体实现: ##### 单点更新 当需要改变原始数中的某一项值时,必须同步调整树状数组对应位置及其祖先结点的信息。算法如下所示: ```cpp void update(int idx, int delta){ while(idx <= n){ t[idx] += delta; idx += lowbit(idx); } } ``` ##### 区间求和 为了计算从索引1到指定索引处所有元素之和,可以采用累加方式逐步访问相关联的节点直到根部为止。伪代码形式呈现如下: ```cpp int query(int idx){ int res = 0; while(idx > 0){ res += t[idx]; idx -= lowbit(idx); } return res; } ``` 上述两部分构成了完整的树状数组框架,适用于处理频繁发生的范围汇总请求与局部修正指令合场景下的优化解决方案[^2]^。 #### 应用实例分析 假设存在一个长度为n的一维数a[],目标是对这个序列执行多次交替进行的修改命令(增加或者减少特定下标的数值大小)同时间歇性询问关于不同片段内的总合状况,则运用BIT将是理想的选择之一因为每次交互都能维持O(logN)的时间消耗级别. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值