Lam NguyenLibrary

Library · Data Structures · range update, range query

Lazy Segment Tree

#pragma once
#include <bits/stdc++.h>
using namespace std;

struct LazySegmentTree {
    int N;
    vector<int> A;
    vector<int> lazy;
    vector<int> st;

    LazySegmentTree(int n, const vector<int>& a) {
        N = n;
        A = a;
        st.resize(4 * N);
        lazy.resize(4 * N);
    } 

    void build(int v, int tl, int tr) {
        if (tl == tr) {
            st[v] = A[tl];
            return;
        }
        int tm = tl + (tr - tl) / 2;
        build(v*2+1, tl, tm);
        build(v*2+2, tm+1, tr);
        st[v] = st[v*2+1] + st[v*2+2];
    }

    // st holds sums, so a pending add counts once per element of the child
    void push(int v, int tl, int tm, int tr) {
        st[v*2+1] += lazy[v] * (tm - tl + 1);
        st[v*2+2] += lazy[v] * (tr - tm);
        lazy[v*2+1] += lazy[v];
        lazy[v*2+2] += lazy[v];
        lazy[v] = 0;
    }

    void update(int v, int tl, int tr, int ql, int qr, int add) {
        if (ql > qr) return;
        if (ql == tl && tr == qr) {
            st[v] += add * (tr - tl + 1);
            lazy[v] += add;
            return;
        }
        int tm = tl + (tr - tl) / 2;
        push(v, tl, tm, tr);
        update(v*2+1, tl, tm, ql, min(tm, qr), add);
        update(v*2+2, tm+1, tr, max(tm+1, ql), qr, add);
        st[v] = st[v*2+1] + st[v*2+2];
    }

    int query(int v, int tl, int tr, int ql, int qr) {
        if (ql > qr) return 0;
        if (ql == tl && tr == qr) return st[v];
        int tm = tl + (tr - tl) / 2;
        push(v, tl, tm, tr);
        int left = query(v*2+1, tl, tm, ql, min(tm, qr));
        int right = query(v*2+2, tm+1, tr, max(tm+1, ql), qr);
        return left + right;
    }
};
class LazySegmentTree:
    # range add, range sum, 0-indexed, inclusive ranges
    def __init__(self, a: list):
        self.N = len(a)
        self.A = list(a)
        self.st = [0] * (4 * max(self.N, 1))
        self.lazy = [0] * (4 * max(self.N, 1))
        if self.N: self.build(0, 0, self.N - 1)

    def build(self, v: int, tl: int, tr: int) -> None:
        if tl == tr:
            self.st[v] = self.A[tl]
            return
        tm = tl + (tr - tl) // 2
        self.build(v * 2 + 1, tl, tm)
        self.build(v * 2 + 2, tm + 1, tr)
        self.st[v] = self.st[v * 2 + 1] + self.st[v * 2 + 2]

    # hand v's pending add to its children; st holds sums, so scale by length
    def push(self, v: int, tl: int, tm: int, tr: int) -> None:
        if self.lazy[v]:
            for c, length in ((v * 2 + 1, tm - tl + 1), (v * 2 + 2, tr - tm)):
                self.st[c] += self.lazy[v] * length
                self.lazy[c] += self.lazy[v]
            self.lazy[v] = 0

    # add x to a[ql..qr]
    def update(self, ql: int, qr: int, x, v: int = 0, tl: int = 0, tr: int = None) -> None:
        if tr is None: tr = self.N - 1
        if ql > qr: return
        if ql == tl and tr == qr:
            self.st[v] += x * (tr - tl + 1)
            self.lazy[v] += x
            return
        tm = tl + (tr - tl) // 2
        self.push(v, tl, tm, tr)
        self.update(ql, min(tm, qr), x, v * 2 + 1, tl, tm)
        self.update(max(tm + 1, ql), qr, x, v * 2 + 2, tm + 1, tr)
        self.st[v] = self.st[v * 2 + 1] + self.st[v * 2 + 2]

    # sum of a[ql..qr]
    def query(self, ql: int, qr: int, v: int = 0, tl: int = 0, tr: int = None):
        if tr is None: tr = self.N - 1
        if ql > qr: return 0
        if ql == tl and tr == qr: return self.st[v]
        tm = tl + (tr - tl) // 2
        self.push(v, tl, tm, tr)
        left = self.query(ql, min(tm, qr), v * 2 + 1, tl, tm)
        right = self.query(max(tm + 1, ql), qr, v * 2 + 2, tm + 1, tr)
        return left + right