リリース・改善中
Algorithm
セグメント木は配列の区間和・区間最小値の問い合わせと値の更新をどちらも O(log n) で処理するデータ構造で、和だけならフェニック木(BIT)が軽量な代替です。
セグメント木は、配列を半分ずつに分けてできる各区間について、和・最小値・最大値などの要約値を保存する二分木です。根は配列全体、葉は要素一つを担当し、内部ノードは二つの子の値をまとめた値を持ちます。そのため、どんな連続区間への問い合わせも、いくつかのノードを組み合わせるだけで答えられます。
累積和は区間和を O(1) で求められますが、要素が一つ変わるだけで O(n) かかります。配列をそのまま使えば更新は速いものの、問い合わせのたびに O(n) かかります。セグメント木は一点更新と区間クエリをどちらも O(log n) で処理するので、値が変わり続けながら区間の問い合わせが次々に届く場面に向いています。遅延伝播を加えれば、区間全体に値を足すような区間更新も O(log n) で扱えます。
まず累積和の限界を理解し、小さな配列で木を手で描いて、クエリと更新がどのノードを通るかをたどるのがおすすめです。続いて短い反復版の実装とフェニック木を自分で書き、区間最小値、転倒数の数え上げ、区間加算と区間和といった定番問題で練習すると、競技プログラミングや技術面接ですぐに使えるようになります。
各ノードが配列の一区間を担当して和や最小値を保存します。結合法則を満たし単位元を持つ演算なら、同じ構造でどれでも扱えます。
要素を一つ変えると葉から根までの一本の経路だけを再計算し、区間クエリは各段で多くても二つのノードを組み合わせて答えます。
区間更新は、その区間を覆うノードにメモを残しておき、子へ降りる必要が生じたときだけ渡すことで O(log n) に収めます。
和のように引き算で戻せる演算なら、長さ n + 1 の配列と短いループだけで同じ計算量を実現するフェニック木(BIT)が使えます。
長さ 2n の配列の後半に要素を置き、前半の各位置に二つの子の和を保存する反復版のセグメント木です。update は葉から根へ上りながら和を再計算し、query は半開区間 [left, right) の両端から上りながら境界にあるノードだけを足します。実行すると 26、17、28 が順に表示されます。
segment_tree.py
class SegmentTree:
"""Iterative segment tree: point update and range sum in O(log n)."""
def __init__(self, values):
self.n = len(values)
self.tree = [0] * self.n + list(values)
for i in range(self.n - 1, 0, -1):
self.tree[i] = self.tree[2 * i] + self.tree[2 * i + 1]
def update(self, index, value):
i = index + self.n
self.tree[i] = value
while i > 1:
i //= 2
self.tree[i] = self.tree[2 * i] + self.tree[2 * i + 1]
def query(self, left, right):
"""Sum of values[left:right] (half-open range)."""
total = 0
lo, hi = left + self.n, right + self.n
while lo < hi:
if lo & 1:
total += self.tree[lo]
lo += 1
if hi & 1:
hi -= 1
total += self.tree[hi]
lo //= 2
hi //= 2
return total
if __name__ == "__main__":
tree = SegmentTree([5, 3, 7, 9, 6, 4, 1, 2])
print(tree.query(2, 6)) # 7 + 9 + 6 + 4 = 26
tree.update(3, 0)
print(tree.query(2, 6)) # 7 + 0 + 6 + 4 = 17
print(tree.query(0, 8)) # 28
python segment_tree.pyインストールから セグメント木 の中心となる考え方まで、6 章で順を追って学びます。
セグメント木 について質問し、経験を共有し、意見を交わす場所です。
まだディスカッションはありません。最初の話題を始めましょう。
コメント 0件
ログイン · ログインするとコメントできます。
最初のコメントを書いてみましょう。