📅  最后修改于: 2023-12-03 15:21:40.462000             🧑  作者: Mango
二维二元索引树,又称二维树状数组或Fenwick树,是树状数组的一种扩展应用,用于处理二维前缀和问题,其时间和空间复杂度均为 $O(n \log n)$。
树状数组是一种快速计算前缀和的数据结构,它可以支持单点修改和区间查询,并且时间复杂度均为 $O(\log n)$。
对于一维数组,树状数组的下标顺序从小到大,每个元素都存储一个前缀和,某个下标处的元素的值表示该位置之前的所有元素之和。
而对于二维数组,我们可以使用两个下标构建树状数组,使其支持二维前缀和操作。
首先,我们需要对目标二维数组 $A$ 进行前缀和处理。具体来说,我们先将第一维下标按顺序排序,再在每一行中计算前缀和。这样,原本的二维数组 $A$ 就被转化成了一个类似于平面坐标系的数据结构 $P$,其中 $P_{i,j}$ 表示第 $i$ 行(按第一维下标排序后)第 $j$ 列之前所有元素之和。
接下来,我们使用两个一维树状数组 $T_1$ 和 $T_2$,其中 $T_1$ 负责处理第一维下标,$T_2$ 负责处理第二维下标。$T_1$ 和 $T_2$ 的长度均为 $n$,表示从 $1$ 到 $n$ 的下标范围。
树状数组 $T_1$ 和 $T_2$ 的元素值表示二维平面中某个矩形的前缀和(包含左上角和右下角)。具体来说,下标为 $(i,j)$ 的 $T_1$ 元素表示第 $i$ 行前 $j$ 个位置的元素之和,下标为 $(i,j)$ 的 $T_2$ 元素表示前 $i$ 行第 $j$ 列之前所有元素之和。
那么对于一个二维前缀和查询,我们可以使用以下步骤:
在查询的过程中,我们使用两个二分查找操作,时间复杂度为 $O(\log^2 n)$,因此整个查询的时间复杂度为 $O(\log^2 n)$。
二维二元索引树主要包含以下两个操作:
以 Python 为例,代码实现如下:
class FenwickTree2D:
def __init__(self, n):
self.n = n
self.tree = [[0] * (n + 1) for _ in range(n + 1)]
def update(self, x, y, v):
i, j = x, y
while i <= self.n:
j = y
while j <= self.n:
self.tree[i][j] += v
j += (j & -j)
i += (i & -i)
def sum(self, x, y):
res = 0
i, j = x, y
while i > 0:
j = y
while j > 0:
res += self.tree[i][j]
j -= (j & -j)
i -= (i & -i)
return res
这里我们使用了一个二维列表 tree
存储树状数组的元素。update
操作用于单点修改,将矩阵上的某个点增加 $v$。sum
操作用于区间查询,计算矩形 $(1,1,x,y)$ 中所有元素之和。