Fu_L's Library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub Fu-L/cp-library

:heavy_check_mark: LazySegmentTree
(src/data_structure/lazy_segment_tree.hpp)

LazySegmentTree

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

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

を $O(\log N)$ で行うことが出来ます.

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

コンストラクタ

(1) lazy_segtree<S, op, e, F, mapping, composition, id> seg(int n);
(2) lazy_segtree<S, op, e, F, mapping, composition, id> seg(vector<S> v);

を定義する必要があります.

計算量

set

void seg.set(int p, S x)

a[p]x を代入します.

制約

計算量

get

S seg.get(int p)

a[p] を返します.

制約

計算量

prod

S seg.prod(int l, int r)

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

制約

計算量

all_prod

S seg.all_prod()

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

計算量

apply

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

制約

計算量

max_right

(1) int seg.max_right<g>(int l)
(2) int seg.max_right<G>(int l, G g)

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

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

制約

計算量

min_left

(1) int seg.min_left<g>(int r)
(2) int seg.min_left<G>(int r, G g)

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

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

制約

計算量

チートシート

よく使う遅延セグ木を置いておきます.

区間加算区間最大値取得

using S = long long;
using F = long long;
constexpr S INF = 8e18;
S op(const S& a, const S& b) {
    return max(a, b);
}
S e() {
    return -INF;
}
S mapping(const F& f, const S& x) {
    return f + x;
}
F composition(const F& f, const F& g) {
    return f + g;
}
F id() {
    return 0;
}

区間更新区間最大値取得

using S = long long;
using F = long long;
constexpr S INF = 8e18;
constexpr F ID = 8e18;
S op(const S& a, const S& b) {
    return max(a, b);
}
S e() {
    return -INF;
}
S mapping(const F& f, const S& x) {
    return (f == ID ? x : f);
}
F composition(const F& f, const F& g) {
    return (f == ID ? g : f);
}
F id() {
    return ID;
}

区間加算区間最小値取得

using S = long long;
using F = long long;
constexpr S INF = 8e18;
S op(const S& a, const S& b) {
    return min(a, b);
}
S e() {
    return INF;
}
S mapping(const F& f, const S& x) {
    return f + x;
}
F composition(const F& f, const F& g) {
    return f + g;
}
F id() {
    return 0;
}

区間更新区間最小値取得

using S = long long;
using F = long long;
constexpr S INF = 8e18;
constexpr F ID = 8e18;
S op(const S& a, const S& b) {
    return min(a, b);
}
S e() {
    return INF;
}
S mapping(const F& f, const S& x) {
    return (f == ID ? x : f);
}
F composition(const F& f, const F& g) {
    return (f == ID ? g : f);
}
F id() {
    return ID;
}

区間加算区間和取得

struct S {
    long long value;
    long long size;
};
using F = long long;
S op(const S& a, const S& b) {
    return {a.value + b.value, a.size + b.size};
}
S e() {
    return {0, 0};
}
S mapping(const F& f, const S& x) {
    return {x.value + f * x.size, x.size};
}
F composition(const F& f, const F& g) {
    return f + g;
}
F id() {
    return 0;
}

区間更新区間和取得

struct S {
    long long value;
    long long size;
};
using F = long long;
constexpr F ID = 8e18;
S op(const S& a, const S& b) {
    return {a.value + b.value, a.size + b.size};
}
S e() {
    return {0, 0};
}
S mapping(const F& f, const S& x) {
    if(f == ID) return x;
    return {f * x.size, x.size};
}
F composition(const F& f, const F& g) {
    return (f == ID ? g : f);
}
F id() {
    return ID;
}

区間アフィン区間和取得

struct S {
    mint a;
    long long size;
};
struct F {
    mint a, b;
};
S op(const S& l, const S& r) {
    return S{l.a + r.a, l.size + r.size};
}
S e() {
    return S{0, 0};
}
S mapping(const F& l, const S& r) {
    return S{r.a * l.a + r.size * l.b, r.size};
}
F composition(const F& l, const F& r) {
    return F{r.a * l.a, r.b * l.a + l.b};
}
F id() {
    return F{1, 0};
}

区間等差数列加算区間和取得

struct S {
    long long value_sum, index_sum, length;
};
struct F {
    long long a, b;
};
S op(const S& a, const S& b) {
    return {a.value_sum + b.value_sum, a.index_sum + b.index_sum, a.length + b.length};
}
S e() {
    return {0, 0, 0};
}
S mapping(const F& f, const S& x) {
    return {x.value_sum + f.a * x.index_sum + f.b * x.length, x.index_sum, x.length};
}
F composition(const F& f, const F& g) {
    return {f.a + g.a, f.b + g.b};
}
F id() {
    return {0, 0};
}

Depends on

Verified with

Code

#pragma once
#include "../template/template.hpp"
template <typename S, auto op, auto e, typename F, auto mapping, auto composition, auto id>
struct LazySegmentTree {
    LazySegmentTree(const int N)
        : LazySegmentTree(vector<S>(N, e())) {}
    LazySegmentTree(const vector<S>& v)
        : n((int)v.size()) {
        size = bit_ceil((unsigned int)n);
        log = countr_zero((unsigned int)size);
        data = vector<S>(2 * size, e());
        lazy = vector<F>(size, id());
        for(int i = 0; i < n; ++i) {
            data[size + i] = v[i];
        }
        for(int i = size - 1; i >= 1; --i) {
            update(i);
        }
    }
    void set(int p, const S& x) {
        assert(0 <= p and p < n);
        p += size;
        for(int i = log; i >= 1; --i) {
            push(p >> i);
        }
        data[p] = x;
        for(int i = 1; i <= log; ++i) {
            update(p >> i);
        }
    }
    S get(int p) {
        assert(0 <= p and p < n);
        p += size;
        for(int i = log; i >= 1; --i) {
            push(p >> i);
        }
        return data[p];
    }
    S prod(int l, int r) {
        assert(0 <= l and l <= r and r <= n);
        if(l == r) return e();
        l += size;
        r += size;
        for(int i = log; i >= 1; --i) {
            if(((l >> i) << i) != l) push(l >> i);
            if(((r >> i) << i) != r) push((r - 1) >> i);
        }
        S sml = e(), smr = e();
        while(l < r) {
            if(l & 1) sml = op(sml, data[l++]);
            if(r & 1) smr = op(data[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }
    S all_prod() const {
        return data[1];
    }
    void apply(int l, int r, const F& f) {
        assert(0 <= l and l <= r and r <= n);
        if(l == r) return;
        l += size;
        r += size;
        for(int i = log; i >= 1; --i) {
            if(((l >> i) << i) != l) push(l >> i);
            if(((r >> i) << i) != r) push((r - 1) >> i);
        }
        {
            int l2 = l, r2 = r;
            while(l < r) {
                if(l & 1) all_apply(l++, f);
                if(r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }
        for(int i = 1; i <= log; ++i) {
            if(((l >> i) << i) != l) update(l >> i);
            if(((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    template <bool (*g)(S)>
    int max_right(const int l) {
        return max_right(l, [](const S& x) { return g(x); });
    }
    template <class G>
    int max_right(int l, const G& g) {
        assert(0 <= l and l <= n);
        assert(g(e()));
        if(l == n) return n;
        l += size;
        for(int i = log; i >= 1; --i) push(l >> i);
        S sm = e();
        do {
            while(l % 2 == 0) l >>= 1;
            if(!g(op(sm, data[l]))) {
                while(l < size) {
                    push(l);
                    l = 2 * l;
                    if(g(op(sm, data[l]))) {
                        sm = op(sm, data[l]);
                        ++l;
                    }
                }
                return l - size;
            }
            sm = op(sm, data[l]);
            ++l;
        } while((l & -l) != l);
        return n;
    }

    template <bool (*g)(S)>
    int min_left(const int r) {
        return min_left(r, [](const S& x) { return g(x); });
    }
    template <class G>
    int min_left(int r, const G& g) {
        assert(0 <= r and r <= n);
        assert(g(e()));
        if(r == 0) return 0;
        r += size;
        for(int i = log; i >= 1; --i) push((r - 1) >> i);
        S sm = e();
        do {
            --r;
            while(r > 1 and (r % 2)) r >>= 1;
            if(!g(op(data[r], sm))) {
                while(r < size) {
                    push(r);
                    r = 2 * r + 1;
                    if(g(op(data[r], sm))) {
                        sm = op(data[r], sm);
                        --r;
                    }
                }
                return r + 1 - size;
            }
            sm = op(data[r], sm);
        } while((r & -r) != r);
        return 0;
    }

   private:
    int n, size, log;
    vector<S> data;
    vector<F> lazy;
    inline void update(const int k) {
        data[k] = op(data[2 * k], data[2 * k + 1]);
    }
    inline void all_apply(const int k, const F& f) {
        data[k] = mapping(f, data[k]);
        if(k < size) {
            lazy[k] = composition(f, lazy[k]);
        }
    }
    inline void push(const int k) {
        all_apply(2 * k, lazy[k]);
        all_apply(2 * k + 1, lazy[k]);
        lazy[k] = id();
    }
    inline unsigned int bit_ceil(const unsigned int n) const {
        unsigned int res = 1;
        while(res < n) res *= 2;
        return res;
    }
    inline int countr_zero(const unsigned int n) const {
        return __builtin_ctz(n);
    }
};
#line 2 "src/template/template.hpp"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using P = pair<long long, long long>;
#define rep(i, a, b) for(long long i = (a); i < (b); ++i)
#define rrep(i, a, b) for(long long i = (a); i >= (b); --i)
constexpr long long inf = 4e18;
struct SetupIO {
    SetupIO() {
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout << fixed << setprecision(30);
    }
} setup_io;
#line 3 "src/data_structure/lazy_segment_tree.hpp"
template <typename S, auto op, auto e, typename F, auto mapping, auto composition, auto id>
struct LazySegmentTree {
    LazySegmentTree(const int N)
        : LazySegmentTree(vector<S>(N, e())) {}
    LazySegmentTree(const vector<S>& v)
        : n((int)v.size()) {
        size = bit_ceil((unsigned int)n);
        log = countr_zero((unsigned int)size);
        data = vector<S>(2 * size, e());
        lazy = vector<F>(size, id());
        for(int i = 0; i < n; ++i) {
            data[size + i] = v[i];
        }
        for(int i = size - 1; i >= 1; --i) {
            update(i);
        }
    }
    void set(int p, const S& x) {
        assert(0 <= p and p < n);
        p += size;
        for(int i = log; i >= 1; --i) {
            push(p >> i);
        }
        data[p] = x;
        for(int i = 1; i <= log; ++i) {
            update(p >> i);
        }
    }
    S get(int p) {
        assert(0 <= p and p < n);
        p += size;
        for(int i = log; i >= 1; --i) {
            push(p >> i);
        }
        return data[p];
    }
    S prod(int l, int r) {
        assert(0 <= l and l <= r and r <= n);
        if(l == r) return e();
        l += size;
        r += size;
        for(int i = log; i >= 1; --i) {
            if(((l >> i) << i) != l) push(l >> i);
            if(((r >> i) << i) != r) push((r - 1) >> i);
        }
        S sml = e(), smr = e();
        while(l < r) {
            if(l & 1) sml = op(sml, data[l++]);
            if(r & 1) smr = op(data[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }
    S all_prod() const {
        return data[1];
    }
    void apply(int l, int r, const F& f) {
        assert(0 <= l and l <= r and r <= n);
        if(l == r) return;
        l += size;
        r += size;
        for(int i = log; i >= 1; --i) {
            if(((l >> i) << i) != l) push(l >> i);
            if(((r >> i) << i) != r) push((r - 1) >> i);
        }
        {
            int l2 = l, r2 = r;
            while(l < r) {
                if(l & 1) all_apply(l++, f);
                if(r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }
        for(int i = 1; i <= log; ++i) {
            if(((l >> i) << i) != l) update(l >> i);
            if(((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    template <bool (*g)(S)>
    int max_right(const int l) {
        return max_right(l, [](const S& x) { return g(x); });
    }
    template <class G>
    int max_right(int l, const G& g) {
        assert(0 <= l and l <= n);
        assert(g(e()));
        if(l == n) return n;
        l += size;
        for(int i = log; i >= 1; --i) push(l >> i);
        S sm = e();
        do {
            while(l % 2 == 0) l >>= 1;
            if(!g(op(sm, data[l]))) {
                while(l < size) {
                    push(l);
                    l = 2 * l;
                    if(g(op(sm, data[l]))) {
                        sm = op(sm, data[l]);
                        ++l;
                    }
                }
                return l - size;
            }
            sm = op(sm, data[l]);
            ++l;
        } while((l & -l) != l);
        return n;
    }

    template <bool (*g)(S)>
    int min_left(const int r) {
        return min_left(r, [](const S& x) { return g(x); });
    }
    template <class G>
    int min_left(int r, const G& g) {
        assert(0 <= r and r <= n);
        assert(g(e()));
        if(r == 0) return 0;
        r += size;
        for(int i = log; i >= 1; --i) push((r - 1) >> i);
        S sm = e();
        do {
            --r;
            while(r > 1 and (r % 2)) r >>= 1;
            if(!g(op(data[r], sm))) {
                while(r < size) {
                    push(r);
                    r = 2 * r + 1;
                    if(g(op(data[r], sm))) {
                        sm = op(data[r], sm);
                        --r;
                    }
                }
                return r + 1 - size;
            }
            sm = op(data[r], sm);
        } while((r & -r) != r);
        return 0;
    }

   private:
    int n, size, log;
    vector<S> data;
    vector<F> lazy;
    inline void update(const int k) {
        data[k] = op(data[2 * k], data[2 * k + 1]);
    }
    inline void all_apply(const int k, const F& f) {
        data[k] = mapping(f, data[k]);
        if(k < size) {
            lazy[k] = composition(f, lazy[k]);
        }
    }
    inline void push(const int k) {
        all_apply(2 * k, lazy[k]);
        all_apply(2 * k + 1, lazy[k]);
        lazy[k] = id();
    }
    inline unsigned int bit_ceil(const unsigned int n) const {
        unsigned int res = 1;
        while(res < n) res *= 2;
        return res;
    }
    inline int countr_zero(const unsigned int n) const {
        return __builtin_ctz(n);
    }
};
Back to top page