Lazy Segtree

モノイド $(S, \cdot: S \times S \to S, e \in S)$と、$S$ から $S$ への写像の集合 $F$ であって、以下の条件を満たすようなものについて使用できるデータ構造です。

長さ $N$ の $S$ の配列に対し、

を $O(\log N)$ で行うことが出来ます。詳細な要件は Appendix を参照してください。

また、このライブラリはオラクルとしてop, e, mapping, composition, idを使用しますが、これらが定数時間で動くものと仮定したときの計算量を記述します。オラクル内部の計算量が $O(f(n))$ である場合はすべての計算量が $O(f(n))$ 倍となります。

コンストラクタ

(1) var seg = initLazySegTree(n:int, op, e, mapping, composition, id)
    var seg = LazySegTreeType(S, F, op, e, mapping, composition, id).init(n)
    var seg = LazySegTree.getType(S, F, op, e, mapping, composition, id).init(n)
(2) var seg = initLazySegTree(v:seq[S], op, e, mapping, composition, id)
    var seg = LazySegTreeType(S, F, op, e, mapping, composition, id).init(v)
    var seg = LazySegTree.getType(S, F, op, e, mapping, composition, id).init(v)

を定義する必要があります。 詳しくは、使用例や こちら も参照してください。

制約

計算量

set

seg.set(p:int, x:S):void
seg[p:int] = x:S

a[p] = x

制約

計算量

get

seg.get(p:int):S
seg[p:int]:S

a[p] を返します。

制約

計算量

prod

seg.prod(l..<r):S
seg[l..<r]:S

op(a[l], ..., a[r - 1]) を、モノイドの性質を満たしていると仮定して計算します。$l = r$ のときは e() を返します。

制約

計算量

all_prod

seg.all_prod():S

op(a[0], ..., a[n-1]) を計算します。$n = 0$ のときは e() を返します。

計算量

apply

(1) seg.apply(p:int, f:F):void
(2) seg.apply(l..<r, f:F):void

制約

計算量

max_right

(1) seg.max_right(l:int, g:(S)->bool):int
(2💻) seg.max_right(l:int, g:(S)->bool):int

以下の条件を両方満たす r を(いずれか一つ)返します。

gが単調だとすれば、g(op(a[l], a[l + 1], ..., a[r - 1])) = true となる最大の r、と解釈することが可能です。

制約

計算量

min_left

(1) seg.min_left(r:int, g:(S)->bool):int
(2💻) int seg.min_left(r:int, g:(S)->bool):int

以下の条件を両方満たす l を(いずれか一つ)返します。

gが単調だとすれば、g(op(a[l], a[l + 1], ..., a[r - 1])) = true となる最小の l、と解釈することが可能です。

制約

計算量

使用例

AC code of https://atcoder.jp/contests/practice2/tasks/practice2_k

import atcoder/header import atcoder/lazysegtree import atcoder/modint import sugar type mint = modint998244353 type S = tuple[a:mint, size:int] type F = tuple[a:mint, b:mint] let op = (l:S, r:S) => (l.a + r.a, l.size + r.size) let e = () => (mint(0), 0) let mapping = (l:F, r:S) => (r.a * l.a + r.size * l.b, r.size) let composition = (l:F, r:F) => (r.a * l.a, r.b * l.a + l.b) let id = () => (mint(1), mint(0)) let n, q = nextInt() var a = newSeq[S](n) for i in 0..<n: let x = nextInt() a[i] = (mint.init(x), 1) var seg = initLazySegTree(a, op, e, mapping, composition, id) for i in 0..<q: let t = nextInt() if t == 0: let l, r, c, d = nextInt() seg.apply(l..<r, (c.mint, d.mint)); else: let l, r = nextInt() echo seg.prod(l..<r).a.val()

AC code of https://atcoder.jp/contests/practice2/tasks/practice2_l

include atcoder/header import atcoder/lazysegtree block: type S = tuple[zero, one, inversion:int] # swapping flag type F = bool proc op(l, r:S):S = (l.zero + r.zero, l.one + r.one, l.inversion + r.inversion + l.one * r.zero) proc e():S = (0,0,0) proc mapping(l:F, r:S):S = if not l: return r return (r.one, r.zero, r.one * r.zero - r.inversion) proc composition(l, r:F):F = (l and not r) or (not l and r) proc id():F = false let n, q = nextInt() var a = newSeq[S](n) for i in 0..<n: let x = nextInt() if x == 0: a[i] = (1, 0, 0) else: a[i] = (0, 1, 0) var seg = init_lazy_segtree(a, op, e, mapping, composition, id) for i in 0..<q: var t, l, r = nextInt() l.dec if t == 1: seg.apply(l..<r, true) else: echo seg.prod(l..<r).inversion