Fenwick木(またはバイナリインデックスツリー)は、配列の要素に対する累積和を効率的に計算するためのデータ構造です。このデータ構造を使用することで、更新とクエリの両方をO(log n)時間で行うことができます。ここでは、Fenwick木の基本操作とその用途について詳しく学びます。
Fenwick木を実装するためには、以下の基本的な操作を理解する必要があります。
以下に、Fenwick木の基本的な実装を示します。この実装では、要素の更新と区間の累積和の計算を行います。
class FenwickTree:
def __init__(self, size):
self.size = size
self.tree = [0] * (size + 1)
def update(self, index, value):
"""index位置の値をvalueだけ更新します。"""
while index <= self.size:
self.tree[index] += value
index += index & -index
def query(self, index):
"""0からindexまでの累積和を返します。"""
total = 0
while index > 0:
total += self.tree[index]
index -= index & -index
return total
def range_query(self, left, right):
"""leftからrightまでの範囲の累積和を返します。"""
return self.query(right) - self.query(left - 1)
__init__
メソッドでは、サイズを指定してFenwick木を初期化します。内部配列tree
は0で初期化されます。
要素の更新:
update
メソッドでは、指定したindex
に対してvalue
を加算します。index
は1から始まるため、配列のインデックスと操作が一致するように注意が必要です。
累積和の計算:
query
メソッドは、0から指定されたindex
までの累積和を計算します。ビット演算を利用して、更新された値を効率的に取得します。
範囲の累積和の計算:
range_query
メソッドでは、指定した範囲の累積和を計算します。これは、query
メソッドを利用して計算されます。次に、Fenwick木を使った具体的な使用例を示します。
# Fenwick木の使用例
if __name__ == "__main__":
# 配列のサイズ
n = 10
fenwick_tree = FenwickTree(n)
# 配列の要素を更新
fenwick_tree.update(1, 5) # index 1に5を加算
fenwick_tree.update(2, 3) # index 2に3を加算
fenwick_tree.update(3, 7) # index 3に7を加算
# 累積和のクエリ
print("1から3までの累積和:", fenwick_tree.range_query(1, 3)) # 5 + 3 + 7 = 15
print("1から2までの累積和:", fenwick_tree.range_query(1, 2)) # 5 + 3 = 8
# 要素を更新
fenwick_tree.update(2, 2) # index 2の値を2増加
# 再度累積和のクエリ
print("1から3までの累積和(更新後):", fenwick_tree.range_query(1, 3)) # 5 + 5 + 7 = 17
この使用例では、次のことを行っています:
Fenwick木は、以下のような多くの用途があります。
Fenwick木は、特に数値の更新や累積和の計算が頻繁に行われる場合に非常に有用なデータ構造です。これにより、複雑な計算を効率的に行うことが可能になります。