cp-library

This documentation is automatically generated by competitive-verifier/competitive-verifier

View the Project on GitHub Ebishu-0309/cp-library

:heavy_check_mark: 可換双対セグ木 (commutative_dual_segment_tree.hpp)

作用素の合成が可換な場合の双対セグ木。実装がより少ない。

コンストラクタ

1. CommutativeDualSegmentTree<F, composition, id>(int n)
2. CommutativeDualSegmentTree<F, composition, id>(vector<F> f)

を受け取り、

  1. 長さ n 、初期値 id() で構築。
  2. f で構築。

計算量

get

F get(int p)

p 番目の作用素を取得。

計算量

apply

void apply(int l, int r, F f)

$k\in[l, r)$ に対して、$k$ 番目の作用素に f を合成。

計算量

Verified with

Code

template <class F, auto composition, auto id>
class CommutativeDualSegmentTree {
    static_assert(is_convertible_v<decltype(composition), function<F(F, F)>>, "composition must work as F(F, F)");
    static_assert(is_convertible_v<decltype(id), function<F()>>, "id must work as F()");

   public:
    CommutativeDualSegmentTree() : CommutativeDualSegmentTree(0) {}
    explicit CommutativeDualSegmentTree(int n) : CommutativeDualSegmentTree(vector<F>(n, id())) {}
    explicit CommutativeDualSegmentTree(vector<F> f) : n(int(f.size())) {
        h = ceil_log2(n);
        siz = (1 << h);
        act = vector<F>(2 * siz, id());
        copy(f.begin(), f.end(), act.begin() + siz);
    }

    F get(int p) {
        assert(0 <= p && p <= n);
        F f = id();
        p += siz;
        for (int i = 0; i <= h; ++i) f = composition(act[p >> i], f);
        return f;
    }

    void apply(int k, F f) { apply(k, k + 1, f); }

    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= n);
        if (l == r) return;
        l += siz;
        r += siz;

        while (l < r) {
            if (l & 1) apply_inner(l++, f);
            if (r & 1) apply_inner(--r, f);
            l >>= 1;
            r >>= 1;
        }
    }

   private:
    int n, h, siz;
    vector<F> act;

    void apply_inner(int k, F f) { act[k] = composition(f, act[k]); }

    int ceil_log2(int x) {
        int res = 0;
        while ((1 << res) < x) ++res;
        return res;
    }
};
#line 1 "commutative_dual_segment_tree.hpp"
template <class F, auto composition, auto id>
class CommutativeDualSegmentTree {
    static_assert(is_convertible_v<decltype(composition), function<F(F, F)>>, "composition must work as F(F, F)");
    static_assert(is_convertible_v<decltype(id), function<F()>>, "id must work as F()");

   public:
    CommutativeDualSegmentTree() : CommutativeDualSegmentTree(0) {}
    explicit CommutativeDualSegmentTree(int n) : CommutativeDualSegmentTree(vector<F>(n, id())) {}
    explicit CommutativeDualSegmentTree(vector<F> f) : n(int(f.size())) {
        h = ceil_log2(n);
        siz = (1 << h);
        act = vector<F>(2 * siz, id());
        copy(f.begin(), f.end(), act.begin() + siz);
    }

    F get(int p) {
        assert(0 <= p && p <= n);
        F f = id();
        p += siz;
        for (int i = 0; i <= h; ++i) f = composition(act[p >> i], f);
        return f;
    }

    void apply(int k, F f) { apply(k, k + 1, f); }

    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= n);
        if (l == r) return;
        l += siz;
        r += siz;

        while (l < r) {
            if (l & 1) apply_inner(l++, f);
            if (r & 1) apply_inner(--r, f);
            l >>= 1;
            r >>= 1;
        }
    }

   private:
    int n, h, siz;
    vector<F> act;

    void apply_inner(int k, F f) { act[k] = composition(f, act[k]); }

    int ceil_log2(int x) {
        int res = 0;
        while ((1 << res) < x) ++res;
        return res;
    }
};
Back to top page