0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

segment tree(遅延)

Last updated at Posted at 2022-04-03

何度も部分加算をして、被らなかった場合、最小値の習得の時にまとめて更新できるので処理が速くなる

遅延なしの場合は部分加算ごとに全要素更新する必要があるが、遅延を使うとlognで一旦保留にできる

template< typename Monoid, typename OperatorMonoid = Monoid >
struct LazySegmentTree
{
    using F = function< Monoid(Monoid, Monoid) >;
    using G = function< Monoid(Monoid, OperatorMonoid) >;
    using H = function< OperatorMonoid(OperatorMonoid, OperatorMonoid) >;
    using P = function< OperatorMonoid(OperatorMonoid, int) >;

    int sz;
    vector< Monoid > data;
    vector< OperatorMonoid > lazy;
    const F f;
    const G g;
    const H h;
    const P p;
    const Monoid M1;
    const OperatorMonoid OM0;

    //size、 関数、 int_max、0
    LazySegmentTree(int n, const F f, const G g, const H h, const P p,
        const Monoid& M1, const OperatorMonoid OM0)
        : f(f), g(g), h(h), p(p), M1(M1), OM0(OM0)
    {
        sz = 1;
        while (sz < n) sz <<= 1; //一番下の行以外
        data.assign(2 * sz, M1); //INFで初期化
        lazy.assign(2 * sz, OM0);//OM0(0)なら更新不要
                                 //代入された値が入る
    }

    void set(int k, const Monoid& x)//k番目にxを代入
    {
        data[k + sz] = x;
    }

    void build()//値をセットした後準備
    {
        for (int k = sz - 1; k > 0; k--) {
            data[k] = f(data[2 * k + 0], data[2 * k + 1]);
        }
    }

    //遅延があれば実行(kの値)
    void propagate(int k, int len)
    {
        if (lazy[k] != OM0) {//0(変更なし)でないなら

            if (k < sz) {//1つ下を更新(上書きを防ぐため)
                lazy[2 * k + 0] = h(lazy[2 * k + 0], lazy[k]);
                lazy[2 * k + 1] = h(lazy[2 * k + 1], lazy[k]);
            }
            data[k] = g(data[k], p(lazy[k], len));
            lazy[k] = OM0;//更新済みにする
        }
    }

    //x:加算する値、  k:基本は1、  [l,r)までxを足す
    Monoid update(int a, int b, const OperatorMonoid& x, int k, int l, int r)//値の範囲加算

    {// k:現在見ているノードの位置  [l,r):data[k]が表している区間

        propagate(k, r - l);//kを更新()
        if (r <= a || b <= l) {//範囲外
            return data[k];
        }
        else if (a <= l && r <= b) {//範囲内
            lazy[k] = h(lazy[k], x);//h:(a+b)
            propagate(k, r - l);//最終決定の部分範囲
            return data[k];
        }
        else {//一部が被る
            return data[k] = f(update(a, b, x, 2 * k + 0, l, (l + r) >> 1),
                update(a, b, x, 2 * k + 1, (l + r) >> 1, r));//下の範囲へ
        }
    }

    Monoid update(int a, int b, const OperatorMonoid& x)
    {
        return update(a, b, x, 1, 0, sz);//全範囲にxを足す
    }

    //最小値を習得
    Monoid query(int a, int b, int k, int l, int r)
    {
        propagate(k, r - l);//kを更新
        if (r <= a || b <= l) {//範囲外
            return M1;
        }
        else if (a <= l && r <= b) {//範囲内
            return data[k];//
        }
        else {
            return f(query(a, b, 2 * k + 0, l, (l + r) >> 1),
                query(a, b, 2 * k + 1, (l + r) >> 1, r));//下の範囲へ
        }
    }

    Monoid query(int a, int b)
    {
        return query(a, b, 1, 0, sz);//全範囲、1から開始
    }

    Monoid operator[](const int& k)
    {
        return query(k, k + 1);
    }
};

//add 区間 min
auto f = [](int a, int b) { return min(a, b); };
auto g = [](int a, int b) { return a + b; };
auto h = [](int a, int b) { return a + b; };
auto p = [](int a, int b) { return a; };
LazySegmentTree< int > seg(N, f, g, h, p, INT_MAX, 0);
auto f = [](int a, int b) { return a + b; };
auto p = [](int a, int b) { return a * b; };
LazySegmentTree< int > seg(N, f, f, f, p, 0, 0);
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?