この記事では遅延セグメント木の「気持ち」を説明します。
通常のセグメント木に関する知識を前提とします。
アルゴリズムの説明のみであり、実装については一切説明していません。
基本的には以下のサイトの記述を、自分好みにリライトしたものです。
beet-aizu.hatenablog.com
○遅延セグメント木とは
半群
作用素モノイドの部分モノイド
の写像
があり、次の(1)~(3)の条件を満たすとする。
(1) の演算、作用素の適用、作用素の合成はいずれもで行える
(2) はにもにも依らずで計算できる
(3) *1
このとき上の長さの列に対する2種類のクエリ(i)(ii)を遅延セグメント木によってで処理することができる
(i)区間更新クエリ:区間と作用素が与えられ、全てのについてをに更新する
(ii)区間計算クエリ:区間が与えられ、を求める
○実現する方法
通常のセグメント木では区間の積の情報を持っていたが、遅延セグメント木ではそれに加え、その区間全体に作用する作用素の情報を持つ。
これだけ。
○でクエリが処理できることの確認
各nodeが長さをの区間の情報をの形で持っているとする。
・区間更新クエリ
区間と作用素が与えられたとする。上から順に次のように各nodeを更新する。
(1)のとき
をに更新する
(2)のとき
何もしない
(3)それ以外のとき
次の3つのことを行う
1.を子nodeに伝播する。即ち、子nodeがであるとき、これをに更新する
(↑これが肝となる遅延伝播)
2.子nodeを再帰的に更新する
3.子nodeの更新結果を元に自身のnodeが持つべき値を計算し、に更新する
以上の操作は個のnodeをで更新するのでとなる。
・区間計算クエリ
区間が与えられたとする。上から順に次のように、各nodeを更新しながら値を計算する
(1)のとき
を返す
(2)それ以外のとき
次の3つのことを行う
1.を子nodeに伝播する。即ち、子nodeがであるとき、これをに更新する
2.自身のnodeを、に更新する
(更新クエリと違って値が変化しないので子を見る必要がない)
3.子nodeを再帰的に呼び出して値を計算したものを返す
以上の操作は個のnodeをで更新/計算するのでとなる。
○自明な例
・区間加算クエリ+区間和クエリ
・区間加算クエリ+区間maxクエリ
・区間変更クエリ+区間和クエリ
・区間変更クエリ+区間maxクエリ
○非自明な例1
の数列が与えられる。次のクエリに答えよ
(i)区間加算クエリ:区間と値が与えられ、全てのについてをに更新する
(ii)区間変更クエリ:区間と値が与えられ、全てのについてをに更新する
(iii)区間計算クエリ:区間が与えられ、を求める
(が写像の合成で閉じていることを確かめよ)
○非自明な例2
の数列とが与えられる。次のクエリに答えよ
(i)区間更新クエリ:区間と値が与えられ、全てのについてをに更新する
(ii)区間計算クエリ:区間が与えられ、を求める
○非自明な例3
とする。上の演算を
により定める。
の数列が与えられる。次のクエリに答えよ
(i)区間更新クエリ:区間と値が与えられ、全てのについてをに更新する
(iii)区間計算クエリ:区間と値が与えられ、を求める
○余談1
仮定(2)を「はに依らずで計算できる」と弱めるとクエリ当たりとなる。
ただし、そのかわりに次の条件を仮定するとで計算可能である。
(2)' が単射かつはに依らずで計算できる
この場合、各nodeはの形で情報を持てばよい。
例えば上で挙げた7つの例は全て(2),(2)'の仮定をともに満たす。
(2)と(2)'の仮定をともに満たす場合、各nodeの情報をの形で持つ流儀の人と、の形で持つ流儀の人がいるため、他人の説明/コードを読む際は、どちらの流儀で書かれたものが注意する必要がある。
○余談1の余談
(2)と(2)'は独立な条件か?
・「(2)を満たし(2)'を満たさないもの」の例としては、区間乗算+区間総積クエリなどがある。
なので、のときを考えるとこれは単射ではない。
しかしこれはで考えることで単射とみなすことができる。
(のへの作用はとする)
本質的にダメな例があったら教えて
・「(2)'を満たし(2)を満たさないもの」の例は思いついてないので誰か教えて
○余談2
上で挙げた例は、全てを適切に取り直すことで、とすることができる。
そうすることが出来ない例があったら教えて
*1: よく考えると課すべき条件はT(xy)=(f(T)x)(f(T)y)だったが、ここを変更すると記事全てを書き直す必要があること、現在の条件でも整合性はあること、の2点を理由に修正は行わない