树状数组 python
时间: 2025-04-03 09:19:41 浏览: 32
### 树状数组简介
树状数组(Binary Indexed Tree,简称 BIT)是一种高效的数据结构,用于处理动态前缀和查询以及单点更新操作。其核心思想是通过构建辅助数组 `e` 来存储部分前缀和的信息,从而加速计算过程。
#### 树状数组的核心概念
树状数组中的每一个节点 `e[i]` 存储的是原数组 `a` 中某些元素的和[^2]。具体来说,对于索引 `i` 的父节点可以通过函数 `lowbit(i)` 计算得到,该函数返回二进制表示下最低位的 1 及之后的部分对应的数值。
以下是低比特函数的定义:
```python
def lowbit(x):
return x & (-x)
```
此函数的作用在于提取整数 `x` 的最低有效位上的 1 所代表的值[^4]。
---
### Python 实现树状数组
下面展示了一个完整的基于 Python 的树状数组实现:
#### 初始化与基本操作
初始化树状数组时,通常需要传入原始数组并将其转换为树状数组形式。以下代码展示了如何完成这一功能:
```python
class BinaryIndexedTree:
def __init__(self, size_or_list):
if isinstance(size_or_list, int): # 如果输入是一个整数,则创建指定大小的零数组
self.size = size_or_list
self.tree = [0] * (size_or_list + 1)
elif isinstance(size_or_list, list): # 如果输入是一个列表,则根据列表初始化
self.size = len(size_or_list)
self.tree = [0] * (self.size + 1)
for idx, val in enumerate(size_or_list, start=1):
self.update(idx, val)
def update(self, index, value):
""" 更新某个位置的值 """
diff = value - (self.query(index) - self.query(index - 1)) # 计算差值
i = index
while i <= self.size:
self.tree[i] += diff
i += lowbit(i)
def query(self, index):
""" 查询前缀和 """
res = 0
i = index
while i > 0:
res += self.tree[i]
i -= lowbit(i)
return res
```
上述代码实现了两个主要方法:`update()` 和 `query()`。前者负责修改特定位置的值;后者则用来获取给定范围内的前缀和。
#### 前缀和的应用实例
假设我们有一个初始数组 `[1, 2, 3, 4, 5, 6, 7]`,可以利用树状数组快速求解其前缀和。例如,要求数组中第 1 到第 4 项的总和,只需调用两次 `query()` 方法即可得出结果:
```python
nums = [1, 2, 3, 4, 5, 6, 7]
# 构建树状数组对象
bit = BinaryIndexedTree(nums)
# 求前缀和
cumulative_sum_up_to_4 = bit.query(4) # 结果应为 1+2+3+4=10
print(cumulative_sum_up_to_4) # 输出: 10
```
这里需要注意的是,在实际应用过程中可能会遇到更复杂的场景,比如区间更新等问题,这些都可以通过对基础版本稍作扩展来支持[^3]。
---
### 蓝桥杯真题解析
为了更好地理解树状数组的实际用途,我们可以尝试解答一道来自蓝桥杯竞赛的经典题目——**逆序对统计问题**。所谓逆序对是指在一个序列里满足条件 \( A_i > A_j \) 并且 \( i < j \) 的一对元素组合的数量。
解决方案如下所示:
```python
from bisect import bisect_left
def count_inversions(arr):
sorted_arr = []
inversion_count = 0
for num in reversed(arr):
pos = bisect_left(sorted_arr, num)
inversion_count += pos
sorted_arr.insert(pos, num)
return inversion_count
arr = [3, 1, 2, 5, 4]
inversion_result = count_inversions(arr)
print(inversion_result) # 应输出 3 对逆序关系
```
尽管这段代码并未直接采用树状数组技术,但它同样能够有效地解决问题。如果改用树状数组方式重写的话,效率会更高尤其是面对大规模数据集的时候[^1]。
---
###
阅读全文
相关推荐
















