遅延評価セグメントツリーです。
この命名には批判があって、遅延伝播セグメントツリーの方が良いという意見も根強いです。
宗教戦争を避けるために、遅延セグ木と呼ぶのがいいかもしれません。
seg = LazySegtree.new(v, e, id)
第1引数は、Integer
またはArray
です。
- 第1引数が
Integer
のn
のとき、長さn
・初期値e
のセグメント木を作ります。 - 第1引数が長さ
n
のArray
のa
のとき、a
をもとにセグメント木を作ります。
第2引数e
は、単位元です。ブロックで二項演算op(x, y)
を定義することで、モノイドを定義する必要があります。
また、インスタンス作成後に、LazySegtree#set_mapping{ }
とLazySegment#set_composition{ }
を用い、適切にインスタンス変数にprocを設定する必要があります。
計算量 O(n)
seg = LazySegtree.new(v, op, e, mapping, compositon, id)
seg = LazySegtree.new(v, e, id, op, mapping, compositon)
前者は、本家ライブラリに合わせた引数の順番。
後者は、procを後ろにまとめた引数の順番で、これは非推奨。
内部で、第2引数がprocかどうかで、場合分けしています。
seg.set(pos, x)
a[pos]
にx
を代入します。
計算量 O(logn)
seg.get(pos)
a[pos]
を返します。
計算量 O(1)
seg.prod(l, r)
op(a[l], ..., a[r - 1])
を返します。引数は半開区間です。l == r
のとき、単位元e
を返します。
制約 0 ≦ l ≦ r ≦ n
計算量 O(logn)
seg.all_prod
op(a[0], ..., a[n - 1])
を返します。サイズが0のときは、単位元e
を返します。
計算量 O(1)
seg.apply(pos, val)
seg.apply(l, r, val)
a[p] = f(a[p])
- 半開区間
i = l..r
についてa[i] = f(a[i])
制約
0 ≦ pos < n
0 ≦ l ≦ r ≦ n
計算量 O(log n)
seg.range_apply(l, r, val)
3引数のapply
を呼んだときに、内部で呼ばれるメソッド。
直接、range_apply
を呼ぶこともできる。
制約 0 ≦ l ≦ r ≦ n
計算量 O(log n)
LazySegtree上で、二分探索をします。
制約 0 ≦ l ≦ n
計算量 O(log n)
LazySegtree上で、二分探索をします。
制約 0 ≦ r ≦ n
計算量 O(log n)
問題のリンクです。Verified済みです。解答はテストコードをご参考ください。
- AIZU ONLINE JUDGE DSL_2_F RMQ and RUQ (旧DSL_2_F)
- AIZU ONLINE JUDGE DSL_2_G RSQ and RAQ (旧DSL_2_G)
- AIZU ONLINE JUDGE DSL_2_H RMQ and RAQ (旧DSL_2_H)
- AIZU ONLINE JUDGE DSL_2_I RSQ and RUQ (旧DSL_2_I)
以下の問題は、Rubyでは実行時間が厳しくTLEになりACできてないです。
下記は、ジャッジにだしてないが、サンプルに正解。max_right
, min_left
を使う問題。
- 当ライブラリ
- 本家ライブラリ
- セグメントツリーについて
- AtCooderLibrary(ACL)のLazySegtreeについて
本家C++ライブラリは独自定義のinternal::ceil_pow2
関数を用いてますが、本ライブラリではRuby既存のメソッドInteger#bit_length
を用いています。そちらの方が計測した結果、高速でした。
本家ACL同様に、初期化の際に配列でも数値でもいいとなっている。
しかし、数値で要素数を指定した際に、ミュータブルなクラスでも同一オブジェクトで要素を作ってしまっている。