Nyaan's Library

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

View on GitHub

:heavy_check_mark: 抽象化領域木
(data-structure-2d/abstract-range-tree.hpp)

Depends on

Verified with

Code

#pragma once

#include <algorithm>
#include <cassert>
#include <functional>
#include <type_traits>
#include <utility>
#include <vector>
using namespace std;

#include "../internal/internal-function.hpp"

// DS ... data_structure_type
// S ... size_type
// T ... value_type
template <typename DS, typename S, typename T,
          typename NewFunc = nyaan_internal::inplace_function<DS*(int), 64>,
          typename AddFunc = nyaan_internal::inplace_function<void(DS&, int, T), 64>,
          typename SumFunc = nyaan_internal::inplace_function<T(DS&, int, int), 64>,
          typename MergeFunc = nyaan_internal::inplace_function<T(T, T), 64>>
struct RangeTree {
  using NEW = NewFunc;
  using ADD = AddFunc;
  using SUM = SumFunc;
  using MRG = MergeFunc;
  using P = pair<S, S>;

  static_assert(is_invocable_r_v<DS*, NEW&, int>,
                "RangeTree NEW must be callable as DS*(int)");
  static_assert(is_invocable_r_v<void, ADD&, DS&, int, T>,
                "RangeTree ADD must be callable as void(DS&, int, T)");
  static_assert(is_invocable_r_v<T, SUM&, DS&, int, int>,
                "RangeTree SUM must be callable as T(DS&, int, int)");
  static_assert(is_invocable_r_v<T, MRG&, T, T>,
                "RangeTree MRG must be callable as T(T, T)");

  S N, M;
  NEW ds_new;
  ADD ds_add;
  SUM ds_sum;
  MRG t_merge;
  const T ti;
  vector<DS*> ds;
  vector<vector<S>> ys;
  vector<P> ps;

  template <typename FNew, typename FAdd, typename FSum, typename FMerge>
  RangeTree(FNew&& nw, FAdd&& ad, FSum&& sm, FMerge&& mrg, const T& ti_)
      : ds_new(std::forward<FNew>(nw)),
        ds_add(std::forward<FAdd>(ad)),
        ds_sum(std::forward<FSum>(sm)),
        t_merge(std::forward<FMerge>(mrg)),
        ti(ti_) {}

  void add_point(S x, S y) { ps.push_back(make_pair(x, y)); }

  void build() {
    sort(begin(ps), end(ps));
    ps.erase(unique(begin(ps), end(ps)), end(ps));
    N = ps.size();
    ds.resize(2 * N, nullptr);
    ys.resize(2 * N);
    for (int i = 0; i < N; ++i) {
      ys[i + N].push_back(ps[i].second);
      ds[i + N] = std::invoke(ds_new, 1);
    }
    for (int i = N - 1; i > 0; --i) {
      ys[i].resize(ys[i << 1].size() + ys[(i << 1) | 1].size());
      merge(begin(ys[(i << 1) | 0]), end(ys[(i << 1) | 0]),
            begin(ys[(i << 1) | 1]), end(ys[(i << 1) | 1]), begin(ys[i]));
      ys[i].erase(unique(begin(ys[i]), end(ys[i])), end(ys[i]));
      ds[i] = std::invoke(ds_new, ys[i].size());
    }
  }

  int id(S x) const {
    return lower_bound(
               begin(ps), end(ps), make_pair(x, S()),
               [](const P& a, const P& b) { return a.first < b.first; }) -
           begin(ps);
  }

  int id(int i, S y) const {
    return lower_bound(begin(ys[i]), end(ys[i]), y) - begin(ys[i]);
  }

  void add(S x, S y, T a) {
    int i = lower_bound(begin(ps), end(ps), make_pair(x, y)) - begin(ps);
    assert(ps[i] == make_pair(x, y));
    for (i += N; i; i >>= 1) std::invoke(ds_add, *ds[i], id(i, y), a);
  }

  T sum(S xl, S yl, S xr, S yr) {
    T L = ti, R = ti;
    int a = id(xl), b = id(xr);
    for (a += N, b += N; a < b; a >>= 1, b >>= 1) {
      if (a & 1)
        L = std::invoke(t_merge, L,
                        std::invoke(ds_sum, *ds[a], id(a, yl), id(a, yr))),
        ++a;
      if (b & 1)
        --b,
            R = std::invoke(t_merge,
                            std::invoke(ds_sum, *ds[b], id(b, yl), id(b, yr)),
                            R);
    }
    return std::invoke(t_merge, L, R);
  }
};

/*
 * @brief 抽象化領域木
 */
#line 2 "data-structure-2d/abstract-range-tree.hpp"

#include <algorithm>
#include <cassert>
#include <functional>
#include <type_traits>
#include <utility>
#include <vector>
using namespace std;

#line 2 "internal/internal-function.hpp"

#include <cstddef>
#line 5 "internal/internal-function.hpp"
#include <memory>
#line 8 "internal/internal-function.hpp"

namespace nyaan_internal {

template <class>
class function_ref;

template <class R, class... Args>
class function_ref<R(Args...)> {
  void* obj_ = nullptr;
  R (*call_obj_)(void*, Args...) = nullptr;
  R (*func_)(Args...) = nullptr;

 public:
  function_ref() noexcept = default;
  function_ref(std::nullptr_t) noexcept {}
  function_ref(R (*f)(Args...)) noexcept : func_(f) {}

  template <
      class F, class Fn = std::remove_reference_t<F>,
      class = std::enable_if_t<
          std::is_lvalue_reference_v<F&&> &&
          !std::is_same_v<std::decay_t<F>, function_ref> &&
          !std::is_pointer_v<std::decay_t<F>> && !std::is_function_v<Fn> &&
          std::is_invocable_r_v<R, Fn&, Args...>>>
  function_ref(F&& f) noexcept {
    obj_ = const_cast<void*>(static_cast<const void*>(std::addressof(f)));
    call_obj_ = [](void* p, Args... args) -> R {
      return std::invoke(*static_cast<Fn*>(p), std::forward<Args>(args)...);
    };
  }

  R operator()(Args... args) const {
    if (call_obj_) {
      return call_obj_(obj_, std::forward<Args>(args)...);
    }
    if (!func_) throw std::bad_function_call();
    return func_(std::forward<Args>(args)...);
  }

  explicit operator bool() const noexcept {
    return call_obj_ != nullptr || func_ != nullptr;
  }
};

template <class, std::size_t Capacity = 32,
          std::size_t Align = alignof(std::max_align_t)>
class inplace_function;

template <class R, class... Args, std::size_t Capacity, std::size_t Align>
class inplace_function<R(Args...), Capacity, Align> {
  using storage_t = typename std::aligned_storage<Capacity, Align>::type;

  storage_t storage_;
  R (*invoke_)(void*, Args&&...) = nullptr;
  void (*copy_)(void*, const void*) = nullptr;
  void (*move_)(void*, void*) = nullptr;
  void (*destroy_)(void*) = nullptr;

  template <class F>
  static R invoke_impl(void* p, Args&&... args) {
    return std::invoke(*static_cast<F*>(p), std::forward<Args>(args)...);
  }

  template <class F>
  static void copy_impl(void* dst, const void* src) {
    new (dst) F(*static_cast<const F*>(src));
  }

  template <class F>
  static void move_impl(void* dst, void* src) {
    if constexpr (std::is_move_constructible_v<F>) {
      new (dst) F(std::move(*static_cast<F*>(src)));
    } else {
      new (dst) F(*static_cast<F*>(src));
    }
  }

  template <class F>
  static void destroy_impl(void* p) {
    static_cast<F*>(p)->~F();
  }

  template <class F>
  void emplace(F&& f) {
    using Fn = std::decay_t<F>;

    static_assert(std::is_invocable_r_v<R, Fn&, Args...>,
                  "inplace_function target is not invocable with this signature");
    static_assert(sizeof(Fn) <= Capacity,
                  "inplace_function target is too large; increase Capacity");
    static_assert(alignof(Fn) <= Align,
                  "inplace_function target alignment is too strict; increase Align");
    static_assert(std::is_copy_constructible_v<Fn>,
                  "inplace_function target must be copy constructible");

    if constexpr (std::is_pointer_v<Fn>) {
      if (f == nullptr) return;
    }

    if constexpr (std::is_move_constructible_v<Fn> ||
                  std::is_lvalue_reference_v<F>) {
      new (&storage_) Fn(std::forward<F>(f));
    } else {
      new (&storage_) Fn(f);
    }
    invoke_ = &invoke_impl<Fn>;
    copy_ = &copy_impl<Fn>;
    move_ = &move_impl<Fn>;
    destroy_ = &destroy_impl<Fn>;
  }

 public:
  inplace_function() noexcept = default;
  inplace_function(std::nullptr_t) noexcept {}

  ~inplace_function() { reset(); }

  inplace_function(const inplace_function& other) {
    if (other) {
      other.copy_(&storage_, &other.storage_);
      invoke_ = other.invoke_;
      copy_ = other.copy_;
      move_ = other.move_;
      destroy_ = other.destroy_;
    }
  }

  inplace_function(inplace_function&& other) {
    if (other) {
      other.move_(&storage_, &other.storage_);
      invoke_ = other.invoke_;
      copy_ = other.copy_;
      move_ = other.move_;
      destroy_ = other.destroy_;
      other.reset();
    }
  }

  template <
      class F, class Fn = std::decay_t<F>,
      class = std::enable_if_t<!std::is_same_v<Fn, inplace_function> &&
                               !std::is_same_v<Fn, std::nullptr_t>>>
  inplace_function(F&& f) {
    emplace(std::forward<F>(f));
  }

  inplace_function& operator=(const inplace_function& other) {
    if (this == &other) return *this;
    reset();
    if (other) {
      other.copy_(&storage_, &other.storage_);
      invoke_ = other.invoke_;
      copy_ = other.copy_;
      move_ = other.move_;
      destroy_ = other.destroy_;
    }
    return *this;
  }

  inplace_function& operator=(inplace_function&& other) {
    if (this == &other) return *this;
    reset();
    if (other) {
      other.move_(&storage_, &other.storage_);
      invoke_ = other.invoke_;
      copy_ = other.copy_;
      move_ = other.move_;
      destroy_ = other.destroy_;
      other.reset();
    }
    return *this;
  }

  template <
      class F, class Fn = std::decay_t<F>,
      class = std::enable_if_t<!std::is_same_v<Fn, inplace_function> &&
                               !std::is_same_v<Fn, std::nullptr_t>>>
  inplace_function& operator=(F&& f) {
    reset();
    emplace(std::forward<F>(f));
    return *this;
  }

  inplace_function& operator=(std::nullptr_t) noexcept {
    reset();
    return *this;
  }

  void reset() noexcept {
    if (destroy_) destroy_(&storage_);
    invoke_ = nullptr;
    copy_ = nullptr;
    move_ = nullptr;
    destroy_ = nullptr;
  }

  explicit operator bool() const noexcept { return invoke_ != nullptr; }

  R operator()(Args... args) const {
    if (!invoke_) throw std::bad_function_call();
    return invoke_(
        const_cast<void*>(static_cast<const void*>(&storage_)),
        std::forward<Args>(args)...);
  }
};

}  // namespace nyaan_internal

using nyaan_internal::function_ref;
using nyaan_internal::inplace_function;
#line 12 "data-structure-2d/abstract-range-tree.hpp"

// DS ... data_structure_type
// S ... size_type
// T ... value_type
template <typename DS, typename S, typename T,
          typename NewFunc = nyaan_internal::inplace_function<DS*(int), 64>,
          typename AddFunc = nyaan_internal::inplace_function<void(DS&, int, T), 64>,
          typename SumFunc = nyaan_internal::inplace_function<T(DS&, int, int), 64>,
          typename MergeFunc = nyaan_internal::inplace_function<T(T, T), 64>>
struct RangeTree {
  using NEW = NewFunc;
  using ADD = AddFunc;
  using SUM = SumFunc;
  using MRG = MergeFunc;
  using P = pair<S, S>;

  static_assert(is_invocable_r_v<DS*, NEW&, int>,
                "RangeTree NEW must be callable as DS*(int)");
  static_assert(is_invocable_r_v<void, ADD&, DS&, int, T>,
                "RangeTree ADD must be callable as void(DS&, int, T)");
  static_assert(is_invocable_r_v<T, SUM&, DS&, int, int>,
                "RangeTree SUM must be callable as T(DS&, int, int)");
  static_assert(is_invocable_r_v<T, MRG&, T, T>,
                "RangeTree MRG must be callable as T(T, T)");

  S N, M;
  NEW ds_new;
  ADD ds_add;
  SUM ds_sum;
  MRG t_merge;
  const T ti;
  vector<DS*> ds;
  vector<vector<S>> ys;
  vector<P> ps;

  template <typename FNew, typename FAdd, typename FSum, typename FMerge>
  RangeTree(FNew&& nw, FAdd&& ad, FSum&& sm, FMerge&& mrg, const T& ti_)
      : ds_new(std::forward<FNew>(nw)),
        ds_add(std::forward<FAdd>(ad)),
        ds_sum(std::forward<FSum>(sm)),
        t_merge(std::forward<FMerge>(mrg)),
        ti(ti_) {}

  void add_point(S x, S y) { ps.push_back(make_pair(x, y)); }

  void build() {
    sort(begin(ps), end(ps));
    ps.erase(unique(begin(ps), end(ps)), end(ps));
    N = ps.size();
    ds.resize(2 * N, nullptr);
    ys.resize(2 * N);
    for (int i = 0; i < N; ++i) {
      ys[i + N].push_back(ps[i].second);
      ds[i + N] = std::invoke(ds_new, 1);
    }
    for (int i = N - 1; i > 0; --i) {
      ys[i].resize(ys[i << 1].size() + ys[(i << 1) | 1].size());
      merge(begin(ys[(i << 1) | 0]), end(ys[(i << 1) | 0]),
            begin(ys[(i << 1) | 1]), end(ys[(i << 1) | 1]), begin(ys[i]));
      ys[i].erase(unique(begin(ys[i]), end(ys[i])), end(ys[i]));
      ds[i] = std::invoke(ds_new, ys[i].size());
    }
  }

  int id(S x) const {
    return lower_bound(
               begin(ps), end(ps), make_pair(x, S()),
               [](const P& a, const P& b) { return a.first < b.first; }) -
           begin(ps);
  }

  int id(int i, S y) const {
    return lower_bound(begin(ys[i]), end(ys[i]), y) - begin(ys[i]);
  }

  void add(S x, S y, T a) {
    int i = lower_bound(begin(ps), end(ps), make_pair(x, y)) - begin(ps);
    assert(ps[i] == make_pair(x, y));
    for (i += N; i; i >>= 1) std::invoke(ds_add, *ds[i], id(i, y), a);
  }

  T sum(S xl, S yl, S xr, S yr) {
    T L = ti, R = ti;
    int a = id(xl), b = id(xr);
    for (a += N, b += N; a < b; a >>= 1, b >>= 1) {
      if (a & 1)
        L = std::invoke(t_merge, L,
                        std::invoke(ds_sum, *ds[a], id(a, yl), id(a, yr))),
        ++a;
      if (b & 1)
        --b,
            R = std::invoke(t_merge,
                            std::invoke(ds_sum, *ds[b], id(b, yl), id(b, yr)),
                            R);
    }
    return std::invoke(t_merge, L, R);
  }
};

/*
 * @brief 抽象化領域木
 */
Back to top page