Skip to content

persistent_affine_segtree.hpp

SECTIONData Structure INCLUDEnoya/persistent_affine_segtree.hpp

保留每次区间仿射修改后的线段树版本,并查询任一版本的区间和。

Complexity: Time: O(log n) per range affine update, range copy, or query. Space: O(n + q log n) nodes for q derived versions.

AC 记录:persistent_range_affine_range_sum

跳到代码 · GitHub ↗

Implementation

当前头文件,省略 include guard;依赖见 #include

/// @complexity Time: O(log n) per range affine update, range copy, or query.
/// Space: O(n + q log n) nodes for q derived versions.

#include <cassert>
#include <vector>

namespace noya {

/// @brief Persistent lazy segment tree for range affine transforms and sums.
/// Every update clones only its two boundary paths. A range copy descends in a
/// destination version and a source version together, replacing fully covered
/// destination nodes by the corresponding immutable source nodes. Lazy tags
/// are pushed only into freshly cloned nodes, so every older root remains
/// unchanged.
template <class T> class persistent_affine_segtree {
public:
  persistent_affine_segtree() = default;

  explicit persistent_affine_segtree(const std::vector<T> &a) { build(a); }

  void build(const std::vector<T> &a) {
    assert(!a.empty());
    n = int(a.size());
    tr.clear();
    tr.reserve(n * 2);
    rt0 = build_node(a, 0, n);
  }

  void reserve(int cap) { tr.reserve(cap); }

  int initial_root() const { return rt0; }

  int apply(int rt, int l, int r, T mul, T add) {
    assert(valid_root(rt));
    assert(0 <= l && l <= r && r <= n);
    return apply_node(rt, 0, n, l, r, mul, add);
  }

  int copy_range(int dr, int sr, int l, int r) {
    assert(valid_root(dr) && valid_root(sr));
    assert(0 <= l && l <= r && r <= n);
    return copy_node(dr, sr, 0, n, l, r);
  }

  T prod(int rt, int l, int r) const {
    assert(valid_root(rt));
    assert(0 <= l && l <= r && r <= n);
    return prod_node(rt, 0, n, l, r, T(1), T(0));
  }

private:
  struct node {
    T sum{};
    T mul = T(1);
    T add{};
    int ls = -1;
    int rs = -1;
  };

  int n = 0;
  int rt0 = -1;
  std::vector<node> tr;

  bool valid_root(int rt) const { return 0 <= rt && rt < int(tr.size()); }

  int make_node(const node &val) {
    tr.push_back(val);
    return int(tr.size()) - 1;
  }

  int clone_node(int id) { return make_node(tr[id]); }

  int build_node(const std::vector<T> &a, int l, int r) {
    if (r - l == 1) {
      return make_node(node{.sum = a[l]});
    }
    int mid = (l + r) / 2;
    int arr = build_node(a, l, mid);
    int b = build_node(a, mid, r);
    return make_node(node{.sum = tr[arr].sum + tr[b].sum, .ls = arr, .rs = b});
  }

  void apply_here(int id, int len, T mul, T add) {
    tr[id].sum = mul * tr[id].sum + add * T(len);
    tr[id].mul *= mul;
    tr[id].add = mul * tr[id].add + add;
  }

  void push_cloned(int id, int ll, int lr) {
    if (tr[id].ls < 0) {
      return;
    }
    T mul = tr[id].mul;
    T add = tr[id].add;
    if (mul == T(1) && add == T(0)) {
      return;
    }
    int arr = clone_node(tr[id].ls);
    int b = clone_node(tr[id].rs);
    tr[id].ls = arr;
    tr[id].rs = b;
    apply_here(arr, ll, mul, add);
    apply_here(b, lr, mul, add);
    tr[id].mul = T(1);
    tr[id].add = T(0);
  }

  void pull(int id) { tr[id].sum = tr[tr[id].ls].sum + tr[tr[id].rs].sum; }

  int apply_node(int id, int l, int r, int ql, int qr, T mul, T add) {
    if (qr <= l || r <= ql) {
      return id;
    }
    int res = clone_node(id);
    if (ql <= l && r <= qr) {
      apply_here(res, r - l, mul, add);
      return res;
    }
    int mid = (l + r) / 2;
    push_cloned(res, mid - l, r - mid);
    int arr = apply_node(tr[res].ls, l, mid, ql, qr, mul, add);
    int b = apply_node(tr[res].rs, mid, r, ql, qr, mul, add);
    tr[res].ls = arr;
    tr[res].rs = b;
    pull(res);
    return res;
  }

  int normalized_clone(int id, int ll, int lr) {
    int res = clone_node(id);
    push_cloned(res, ll, lr);
    return res;
  }

  int copy_node(int dst, int src, int l, int r, int ql, int qr) {
    if (qr <= l || r <= ql) {
      return dst;
    }
    if (ql <= l && r <= qr) {
      return src;
    }
    int mid = (l + r) / 2;
    int dc = normalized_clone(dst, mid - l, r - mid);
    int sc = normalized_clone(src, mid - l, r - mid);
    int arr = copy_node(tr[dc].ls, tr[sc].ls, l, mid, ql, qr);
    int b = copy_node(tr[dc].rs, tr[sc].rs, mid, r, ql, qr);
    tr[dc].ls = arr;
    tr[dc].rs = b;
    pull(dc);
    return dc;
  }

  T prod_node(int id, int l, int r, int ql, int qr, T am, T aa) const {
    if (qr <= l || r <= ql) {
      return T(0);
    }
    if (ql <= l && r <= qr) {
      return am * tr[id].sum + aa * T(r - l);
    }
    T mul = am * tr[id].mul;
    T add = am * tr[id].add + aa;
    int mid = (l + r) / 2;
    return prod_node(tr[id].ls, l, mid, ql, qr, mul, add) +
           prod_node(tr[id].rs, mid, r, ql, qr, mul, add);
  }
};

} // namespace noya
#ifndef NOYA_PERSISTENT_AFFINE_SEGTREE_HPP
#define NOYA_PERSISTENT_AFFINE_SEGTREE_HPP 1

/// @complexity Time: O(log n) per range affine update, range copy, or query.
/// Space: O(n + q log n) nodes for q derived versions.

#include <cassert>
#include <vector>

namespace noya {

/// @brief Persistent lazy segment tree for range affine transforms and sums.
/// Every update clones only its two boundary paths. A range copy descends in a
/// destination version and a source version together, replacing fully covered
/// destination nodes by the corresponding immutable source nodes. Lazy tags
/// are pushed only into freshly cloned nodes, so every older root remains
/// unchanged.
template <class T> class persistent_affine_segtree {
public:
  persistent_affine_segtree() = default;

  explicit persistent_affine_segtree(const std::vector<T> &a) { build(a); }

  void build(const std::vector<T> &a) {
    assert(!a.empty());
    n = int(a.size());
    tr.clear();
    tr.reserve(n * 2);
    rt0 = build_node(a, 0, n);
  }

  void reserve(int cap) { tr.reserve(cap); }

  int initial_root() const { return rt0; }

  int apply(int rt, int l, int r, T mul, T add) {
    assert(valid_root(rt));
    assert(0 <= l && l <= r && r <= n);
    return apply_node(rt, 0, n, l, r, mul, add);
  }

  int copy_range(int dr, int sr, int l, int r) {
    assert(valid_root(dr) && valid_root(sr));
    assert(0 <= l && l <= r && r <= n);
    return copy_node(dr, sr, 0, n, l, r);
  }

  T prod(int rt, int l, int r) const {
    assert(valid_root(rt));
    assert(0 <= l && l <= r && r <= n);
    return prod_node(rt, 0, n, l, r, T(1), T(0));
  }

private:
  struct node {
    T sum{};
    T mul = T(1);
    T add{};
    int ls = -1;
    int rs = -1;
  };

  int n = 0;
  int rt0 = -1;
  std::vector<node> tr;

  bool valid_root(int rt) const { return 0 <= rt && rt < int(tr.size()); }

  int make_node(const node &val) {
    tr.push_back(val);
    return int(tr.size()) - 1;
  }

  int clone_node(int id) { return make_node(tr[id]); }

  int build_node(const std::vector<T> &a, int l, int r) {
    if (r - l == 1) {
      return make_node(node{.sum = a[l]});
    }
    int mid = (l + r) / 2;
    int arr = build_node(a, l, mid);
    int b = build_node(a, mid, r);
    return make_node(node{.sum = tr[arr].sum + tr[b].sum, .ls = arr, .rs = b});
  }

  void apply_here(int id, int len, T mul, T add) {
    tr[id].sum = mul * tr[id].sum + add * T(len);
    tr[id].mul *= mul;
    tr[id].add = mul * tr[id].add + add;
  }

  void push_cloned(int id, int ll, int lr) {
    if (tr[id].ls < 0) {
      return;
    }
    T mul = tr[id].mul;
    T add = tr[id].add;
    if (mul == T(1) && add == T(0)) {
      return;
    }
    int arr = clone_node(tr[id].ls);
    int b = clone_node(tr[id].rs);
    tr[id].ls = arr;
    tr[id].rs = b;
    apply_here(arr, ll, mul, add);
    apply_here(b, lr, mul, add);
    tr[id].mul = T(1);
    tr[id].add = T(0);
  }

  void pull(int id) { tr[id].sum = tr[tr[id].ls].sum + tr[tr[id].rs].sum; }

  int apply_node(int id, int l, int r, int ql, int qr, T mul, T add) {
    if (qr <= l || r <= ql) {
      return id;
    }
    int res = clone_node(id);
    if (ql <= l && r <= qr) {
      apply_here(res, r - l, mul, add);
      return res;
    }
    int mid = (l + r) / 2;
    push_cloned(res, mid - l, r - mid);
    int arr = apply_node(tr[res].ls, l, mid, ql, qr, mul, add);
    int b = apply_node(tr[res].rs, mid, r, ql, qr, mul, add);
    tr[res].ls = arr;
    tr[res].rs = b;
    pull(res);
    return res;
  }

  int normalized_clone(int id, int ll, int lr) {
    int res = clone_node(id);
    push_cloned(res, ll, lr);
    return res;
  }

  int copy_node(int dst, int src, int l, int r, int ql, int qr) {
    if (qr <= l || r <= ql) {
      return dst;
    }
    if (ql <= l && r <= qr) {
      return src;
    }
    int mid = (l + r) / 2;
    int dc = normalized_clone(dst, mid - l, r - mid);
    int sc = normalized_clone(src, mid - l, r - mid);
    int arr = copy_node(tr[dc].ls, tr[sc].ls, l, mid, ql, qr);
    int b = copy_node(tr[dc].rs, tr[sc].rs, mid, r, ql, qr);
    tr[dc].ls = arr;
    tr[dc].rs = b;
    pull(dc);
    return dc;
  }

  T prod_node(int id, int l, int r, int ql, int qr, T am, T aa) const {
    if (qr <= l || r <= ql) {
      return T(0);
    }
    if (ql <= l && r <= qr) {
      return am * tr[id].sum + aa * T(r - l);
    }
    T mul = am * tr[id].mul;
    T add = am * tr[id].add + aa;
    int mid = (l + r) / 2;
    return prod_node(tr[id].ls, l, mid, ql, qr, mul, add) +
           prod_node(tr[id].rs, mid, r, ql, qr, mul, add);
  }
};

} // namespace noya

#endif // NOYA_PERSISTENT_AFFINE_SEGTREE_HPP
#include <cassert>
#include <vector>

/// @complexity Time: O(log n) per range affine update, range copy, or query.
/// Space: O(n + q log n) nodes for q derived versions.

namespace noya {

/// @brief Persistent lazy segment tree for range affine transforms and sums.
/// Every update clones only its two boundary paths. A range copy descends in a
/// destination version and a source version together, replacing fully covered
/// destination nodes by the corresponding immutable source nodes. Lazy tags
/// are pushed only into freshly cloned nodes, so every older root remains
/// unchanged.
template <class T> class persistent_affine_segtree {
public:
  persistent_affine_segtree() = default;

  explicit persistent_affine_segtree(const std::vector<T> &a) { build(a); }

  void build(const std::vector<T> &a) {
    assert(!a.empty());
    n = int(a.size());
    tr.clear();
    tr.reserve(n * 2);
    rt0 = build_node(a, 0, n);
  }

  void reserve(int cap) { tr.reserve(cap); }

  int initial_root() const { return rt0; }

  int apply(int rt, int l, int r, T mul, T add) {
    assert(valid_root(rt));
    assert(0 <= l && l <= r && r <= n);
    return apply_node(rt, 0, n, l, r, mul, add);
  }

  int copy_range(int dr, int sr, int l, int r) {
    assert(valid_root(dr) && valid_root(sr));
    assert(0 <= l && l <= r && r <= n);
    return copy_node(dr, sr, 0, n, l, r);
  }

  T prod(int rt, int l, int r) const {
    assert(valid_root(rt));
    assert(0 <= l && l <= r && r <= n);
    return prod_node(rt, 0, n, l, r, T(1), T(0));
  }

private:
  struct node {
    T sum{};
    T mul = T(1);
    T add{};
    int ls = -1;
    int rs = -1;
  };

  int n = 0;
  int rt0 = -1;
  std::vector<node> tr;

  bool valid_root(int rt) const { return 0 <= rt && rt < int(tr.size()); }

  int make_node(const node &val) {
    tr.push_back(val);
    return int(tr.size()) - 1;
  }

  int clone_node(int id) { return make_node(tr[id]); }

  int build_node(const std::vector<T> &a, int l, int r) {
    if (r - l == 1) {
      return make_node(node{.sum = a[l]});
    }
    int mid = (l + r) / 2;
    int arr = build_node(a, l, mid);
    int b = build_node(a, mid, r);
    return make_node(node{.sum = tr[arr].sum + tr[b].sum, .ls = arr, .rs = b});
  }

  void apply_here(int id, int len, T mul, T add) {
    tr[id].sum = mul * tr[id].sum + add * T(len);
    tr[id].mul *= mul;
    tr[id].add = mul * tr[id].add + add;
  }

  void push_cloned(int id, int ll, int lr) {
    if (tr[id].ls < 0) {
      return;
    }
    T mul = tr[id].mul;
    T add = tr[id].add;
    if (mul == T(1) && add == T(0)) {
      return;
    }
    int arr = clone_node(tr[id].ls);
    int b = clone_node(tr[id].rs);
    tr[id].ls = arr;
    tr[id].rs = b;
    apply_here(arr, ll, mul, add);
    apply_here(b, lr, mul, add);
    tr[id].mul = T(1);
    tr[id].add = T(0);
  }

  void pull(int id) { tr[id].sum = tr[tr[id].ls].sum + tr[tr[id].rs].sum; }

  int apply_node(int id, int l, int r, int ql, int qr, T mul, T add) {
    if (qr <= l || r <= ql) {
      return id;
    }
    int res = clone_node(id);
    if (ql <= l && r <= qr) {
      apply_here(res, r - l, mul, add);
      return res;
    }
    int mid = (l + r) / 2;
    push_cloned(res, mid - l, r - mid);
    int arr = apply_node(tr[res].ls, l, mid, ql, qr, mul, add);
    int b = apply_node(tr[res].rs, mid, r, ql, qr, mul, add);
    tr[res].ls = arr;
    tr[res].rs = b;
    pull(res);
    return res;
  }

  int normalized_clone(int id, int ll, int lr) {
    int res = clone_node(id);
    push_cloned(res, ll, lr);
    return res;
  }

  int copy_node(int dst, int src, int l, int r, int ql, int qr) {
    if (qr <= l || r <= ql) {
      return dst;
    }
    if (ql <= l && r <= qr) {
      return src;
    }
    int mid = (l + r) / 2;
    int dc = normalized_clone(dst, mid - l, r - mid);
    int sc = normalized_clone(src, mid - l, r - mid);
    int arr = copy_node(tr[dc].ls, tr[sc].ls, l, mid, ql, qr);
    int b = copy_node(tr[dc].rs, tr[sc].rs, mid, r, ql, qr);
    tr[dc].ls = arr;
    tr[dc].rs = b;
    pull(dc);
    return dc;
  }

  T prod_node(int id, int l, int r, int ql, int qr, T am, T aa) const {
    if (qr <= l || r <= ql) {
      return T(0);
    }
    if (ql <= l && r <= qr) {
      return am * tr[id].sum + aa * T(r - l);
    }
    T mul = am * tr[id].mul;
    T add = am * tr[id].add + aa;
    int mid = (l + r) / 2;
    return prod_node(tr[id].ls, l, mid, ql, qr, mul, add) +
           prod_node(tr[id].rs, mid, r, ql, qr, mul, add);
  }
};

} // namespace noya