Library

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

View the Project on GitHub jellc/Library

:heavy_check_mark: Lazy Segment Tree
(src/data_structure/segment_tree/lazy.hpp)

Depends on

Verified with

Code

#pragma once

/**
 * @file lazy.hpp
 * @brief Lazy Segment Tree
 */

#include <cassert>
#include <queue>
#include <vector>

#include "src/algebra/system/monoid.hpp"
#include "src/algebra/system/operation.hpp"
#include "src/utils/sfinae.hpp"
#include "waitings.hpp"

namespace workspace {

template <class _Monoid, class _End,
          class Monoid_container = std::vector<_Monoid>,
          class Endomorphism_container = std::vector<_End>>
class lazy_segment_tree {
  static_assert(
      std::is_same<_Monoid, typename Monoid_container::value_type>::value);

  static_assert(
      std::is_same<_End, typename Endomorphism_container::value_type>::value);

  static_assert(has_binary_plus<_Monoid>::value,
                "\'_Monoid\' has no proper binary \'operator+\'.");

  static_assert(has_binary_multiplies<_End>::value,
                "\'_End\' has no proper binary \'operator*\'.");

  static_assert(has_binary_multiplies<_Monoid, _End>::value,
                "\'_End\' is not applicable to \'_Monoid\'.");

  size_t size_orig, height, size_ext;
  Monoid_container data;
  Endomorphism_container lazy;
  internal::waitings wait;

  void repair() {
    while (!wait.empty()) {
      const size_t __i = wait.pop() >> 1;
      if (__i && wait.push(__i)) pull(__i);
    }
  }

  void _apply(size_t node, const _End &__e) {
    data[node] = data[node] * __e;
    if (node < size_ext) lazy[node] = lazy[node] * __e;
  }

  void push(size_t node) {
    _apply(node << 1, lazy[node]);
    _apply(node << 1 | 1, lazy[node]);
    lazy[node] = _End{};
  }

  void pull(size_t node) { data[node] = data[node << 1] + data[node << 1 | 1]; }

  template <class _Pred>
  size_t left_partition_subtree(size_t node, _Monoid mono, _Pred __pred) {
    assert(node);
    while (node < size_ext) {
      push(node);
      const _Monoid __tmp = data[(node <<= 1) | 1] + mono;
      if (__pred(__tmp))
        mono = std::move(__tmp);
      else
        ++node;
    }
    return ++node -= size_ext;
  }

  template <class _Pred>
  size_t right_partition_subtree(size_t node, _Monoid mono, _Pred __pred) {
    assert(node);
    while (node < size_ext) {
      push(node);
      const _Monoid __tmp = mono + data[node <<= 1];
      if (__pred(__tmp)) ++node, mono = std::move(__tmp);
    }
    return (node -= size_ext) < size_orig ? node : size_orig;
  }

 public:
  class iterator {
    lazy_segment_tree *__p;
    size_t __i;

   public:
    using difference_type = typename std::make_signed<size_t>::type;
    using value_type = _Monoid;
    using reference = _Monoid &;
    using pointer = iterator;
    using iterator_category = std::random_access_iterator_tag;

    /**
     * @brief Construct a new iterator object
     *
     */
    iterator() = default;

    /**
     * @brief Construct a new iterator object
     *
     * @param __p Pointer to a segment tree object
     * @param __i Index
     */
    iterator(lazy_segment_tree *__p, size_t __i) : __p(__p), __i(__i) {}

    bool operator==(iterator const &rhs) const {
      return __p == rhs.__p && __i == rhs.__i;
    }
    bool operator!=(iterator const &rhs) const { return !operator==(rhs); }

    bool operator<(iterator const &rhs) const { return __i < rhs.__i; }
    bool operator>(iterator const &rhs) const { return __i > rhs.__i; }
    bool operator<=(iterator const &rhs) const { return __i <= rhs.__i; }
    bool operator>=(iterator const &rhs) const { return __i >= rhs.__i; }

    iterator &operator++() { return ++__i, *this; }
    iterator &operator--() { return --__i, *this; }

    difference_type operator-(iterator const &rhs) const {
      return __i - rhs.__i;
    }

    /**
     * @brief
     *
     * @return reference
     */
    reference operator*() const { return __p->operator[](__i); }
  };

  using value_type = typename iterator::value_type;
  using reference = typename iterator::reference;

  iterator begin() { return {this, 0}; }
  iterator end() { return {this, size_orig}; }

  auto rbegin() { return std::make_reverse_iterator(end()); }
  auto rend() { return std::make_reverse_iterator(begin()); }

  lazy_segment_tree(size_t __n = 0)
      : size_orig{__n},
        height(__n > 1 ? 32 - __builtin_clz(__n - 1) : 0),
        size_ext{1u << height},
        data(size_ext << 1),
        lazy(size_ext),
        wait(size_ext << 1) {}

  lazy_segment_tree(size_t __n, const _Monoid &init) : lazy_segment_tree(__n) {
    std::fill_n(std::next(std::begin(data), size_ext), __n, init);
    for (size_t i{size_ext}; --i;) pull(i);
  }

  template <class iter_type, class value_type = typename std::iterator_traits<
                                 iter_type>::value_type>
  lazy_segment_tree(iter_type first, iter_type last)
      : size_orig(std::distance(first, last)),
        height(size_orig > 1 ? 32 - __builtin_clz(size_orig - 1) : 0),
        size_ext{1u << height},
        data(size_ext << 1),
        lazy(size_ext),
        wait(size_ext << 1) {
    static_assert(std::is_constructible<_Monoid, value_type>::value,
                  "_Monoid(iter_type::value_type) is not constructible.");
    for (auto iter{std::next(std::begin(data), size_ext)};
         iter != std::end(data) && first != last; ++iter, ++first)
      *iter = _Monoid(*first);
    for (size_t i{size_ext}; --i;) pull(i);
  }

  /**
   * @return Number of elements.
   */
  size_t size() const { return size_orig; }

  /**
   * @param __i Index of the element
   * @return Reference to the element.
   */
  _Monoid &operator[](size_t __i) {
    assert(__i < size_orig);
    __i |= size_ext;
    wait.push(__i);
    for (size_t i = height; i; --i) push(__i >> i);
    return data[__i];
  }

  void apply(const _End &__e) { apply(0, size_orig, __e); }

  void apply(size_t __i, const _End &__e) { apply(__i, __i + 1, __e); }

  void apply(size_t first, size_t last, const _End &__e) {
    assert(last <= size_orig);
    repair();
    if (first >= last) return;
    first += size_ext, last += size_ext;
    --last;
    for (size_t i = height; i; --i) push(first >> i), push(last >> i);
    ++last;
    for (size_t l = first, r = last; l != r; l >>= 1, r >>= 1) {
      if (l & 1) _apply(l++, __e);
      if (r & 1) _apply(--r, __e);
    }
    for (first >>= __builtin_ffs(first); first; first >>= 1) pull(first);
    for (last >>= __builtin_ffs(last); last; last >>= 1) pull(last);
  }

  /**
   * @param first Left end, inclusive
   * @param last Right end, exclusive
   * @return Sum of elements in the interval.
   */
  _Monoid fold(size_t first, size_t last) {
    assert(last <= size_orig);
    repair();
    if (first >= last) return _Monoid{};
    first += size_ext, last += size_ext - 1;
    _Monoid left_val{}, right_val{};
    for (size_t l = first, r = last + 1; l != r; l >>= 1, r >>= 1) {
      if (l & 1) left_val = left_val + data[l++];
      if (r & 1) right_val = data[--r] + right_val;
      left_val = left_val * lazy[first >>= 1];
      right_val = right_val * lazy[last >>= 1];
    }
    while (first >>= 1, last >>= 1) {
      left_val = left_val * lazy[first];
      right_val = right_val * lazy[last];
    }
    return left_val + right_val;
  }

  /**
   * @return Sum of all elements.
   */
  _Monoid fold() {
    repair();
    return data[1];
  }

  /**
   * @brief Binary search for the partition point.
   * @param __r Right fixed end of the interval, exclusive
   * @param __pred Predicate in the form of 'bool(_Monoid)'
   * @return Left end of the extremal interval satisfying the condition,
   * inclusive.
   */
  template <class _Pred> size_t left_partition(size_t __r, _Pred __pred) {
    assert(__r <= size_orig);
    repair();
    __r += size_ext - 1;
    for (size_t i{height}; i; --i) push(__r >> i);
    ++__r;
    _Monoid mono{};
    for (size_t __l{size_ext}, step{}; __l != __r;
         __l >>= 1, __r >>= 1, ++step) {
      if ((__l & 1) != (__r & 1)) {
        const _Monoid __tmp = data[--__r] + mono;
        if (!__pred(__tmp))
          return left_partition_subtree(__r, std::move(mono), __pred);
        mono = std::move(__tmp);
      }
    }
    return 0;
  }

  /**
   * @brief Binary search for the partition point.
   * @param __l Left fixed end of the interval, inclusive
   * @param __pred Predicate in the form of 'bool(_Monoid)'
   * @return Right end of the extremal interval satisfying the condition,
   * exclusive.
   */
  template <class _Pred> size_t right_partition(size_t __l, _Pred __pred) {
    assert(__l <= size_orig);
    repair();
    __l += size_ext;
    for (size_t i{height}; i; --i) push(__l >> i);
    _Monoid mono{};
    for (size_t __r{size_ext << 1}, step{}; __l != __r;
         __l >>= 1, __r >>= 1, ++step) {
      if ((__l & 1) != (__r & 1)) {
        const _Monoid __tmp = mono + data[__l];
        if (!__pred(__tmp))
          return right_partition_subtree(__l, std::move(mono), __pred);
        mono = std::move(__tmp);
        ++__l;
      }
    }
    return size_orig;
  }
};

}  // namespace workspace
#line 2 "src/data_structure/segment_tree/lazy.hpp"

/**
 * @file lazy.hpp
 * @brief Lazy Segment Tree
 */

#include <cassert>
#include <queue>
#include <vector>

#line 2 "src/algebra/system/monoid.hpp"
#include <limits>

namespace workspace {
template <class T, class E = T> struct min_monoid {
  using value_type = T;
  static T min, max;
  T value;
  min_monoid() : value(max) {}
  min_monoid(const T &value) : value(value) {}
  operator T() const { return value; }
  min_monoid operator+(const min_monoid &rhs) const {
    return value < rhs.value ? *this : rhs;
  }
  min_monoid operator*(const E &rhs) const;
};

template <class T, class E>
T min_monoid<T, E>::min = std::numeric_limits<T>::min() / 2;
template <class T, class E>
T min_monoid<T, E>::max = std::numeric_limits<T>::max() / 2;

template <class T, class E = T> struct max_monoid : min_monoid<T, E> {
  using base = min_monoid<T, E>;
  using base::min_monoid;
  max_monoid() : base(base::min) {}
  max_monoid operator+(const max_monoid &rhs) const {
    return !(base::value < rhs.value) ? *this : rhs;
  }
  max_monoid operator*(const E &rhs) const;
};
}
#line 2 "src/algebra/system/operation.hpp"

/**
 * @file operation.hpp
 * @brief Operation Traits
 */

#include <functional>
#include <type_traits>

#line 2 "lib/cxx17"

#line 2 "lib/cxx14"

#ifndef _CXX14_CONSTEXPR
#if __cplusplus >= 201402L
#define _CXX14_CONSTEXPR constexpr
#else
#define _CXX14_CONSTEXPR
#endif
#endif
#line 4 "lib/cxx17"

#ifndef _CXX17_CONSTEXPR
#if __cplusplus >= 201703L
#define _CXX17_CONSTEXPR constexpr
#else
#define _CXX17_CONSTEXPR
#endif
#endif

#ifndef _CXX17_STATIC_ASSERT
#if __cplusplus >= 201703L
#define _CXX17_STATIC_ASSERT static_assert
#else
#define _CXX17_STATIC_ASSERT assert
#endif
#endif

#include <iterator>

#if __cplusplus < 201703L

namespace std {

/**
 *  @brief  Return the size of a container.
 *  @param  __cont  Container.
 */
template <typename _Container>
constexpr auto size(const _Container& __cont) noexcept(noexcept(__cont.size()))
    -> decltype(__cont.size()) {
  return __cont.size();
}

/**
 *  @brief  Return the size of an array.
 */
template <typename _Tp, size_t _Nm>
constexpr size_t size(const _Tp (&)[_Nm]) noexcept {
  return _Nm;
}

/**
 *  @brief  Return whether a container is empty.
 *  @param  __cont  Container.
 */
template <typename _Container>
[[nodiscard]] constexpr auto empty(const _Container& __cont) noexcept(
    noexcept(__cont.empty())) -> decltype(__cont.empty()) {
  return __cont.empty();
}

/**
 *  @brief  Return whether an array is empty (always false).
 */
template <typename _Tp, size_t _Nm>
[[nodiscard]] constexpr bool empty(const _Tp (&)[_Nm]) noexcept {
  return false;
}

/**
 *  @brief  Return whether an initializer_list is empty.
 *  @param  __il  Initializer list.
 */
template <typename _Tp>
[[nodiscard]] constexpr bool empty(initializer_list<_Tp> __il) noexcept {
  return __il.size() == 0;
}

struct monostate {};

}  // namespace std

#else

#include <variant>

#endif
#line 12 "src/algebra/system/operation.hpp"

namespace workspace {

// Unary `+`
template <class _Tp>
using require_unary_plus = std::enable_if_t<
    std::is_convertible<decltype(+std::declval<const _Tp &>()), _Tp>::value>;

template <class _Tp, class = void> struct has_unary_plus : std::false_type {};

template <class _Tp>
struct has_unary_plus<_Tp, require_unary_plus<_Tp>> : std::true_type {};

// Unary `-`
template <class _Tp>
using require_unary_minus = std::enable_if_t<
    std::is_convertible<decltype(-std::declval<const _Tp &>()), _Tp>::value>;

template <class _Tp, class = void> struct has_unary_minus : std::false_type {};

template <class _Tp>
struct has_unary_minus<_Tp, require_unary_minus<_Tp>> : std::true_type {};

// Binary `+`
template <class _Tp1, class _Tp2 = _Tp1>
using require_binary_plus =
    std::enable_if_t<std::is_convertible<decltype(std::declval<const _Tp1 &>() +
                                                  std::declval<const _Tp2 &>()),
                                         _Tp1>::value>;

template <class _Tp1, class _Tp2 = _Tp1, class = void>
struct has_binary_plus : std::false_type {};

template <class _Tp1, class _Tp2>
struct has_binary_plus<_Tp1, _Tp2, require_binary_plus<_Tp1, _Tp2>>
    : std::true_type {};

// Binary `-`
template <class _Tp1, class _Tp2 = _Tp1>
using require_binary_minus =
    std::__void_t<decltype(std::declval<const _Tp1 &>() -
                           std::declval<const _Tp2 &>())>;

template <class _Tp1, class _Tp2 = _Tp1, class = void>
struct has_binary_minus : std::false_type {};

template <class _Tp1, class _Tp2>
struct has_binary_minus<_Tp1, _Tp2, require_binary_minus<_Tp1, _Tp2>>
    : std::true_type {};

// Binary `*`
template <class _Tp1, class _Tp2 = _Tp1>
using require_binary_multiplies =
    std::enable_if_t<std::is_convertible<decltype(std::declval<const _Tp1 &>() *
                                                  std::declval<const _Tp2 &>()),
                                         _Tp1>::value>;

template <class _Tp1, class _Tp2 = _Tp1, class = void>
struct has_binary_multiplies : std::false_type {};

template <class _Tp1, class _Tp2>
struct has_binary_multiplies<_Tp1, _Tp2, require_binary_multiplies<_Tp1, _Tp2>>
    : std::true_type {};

// Binary `/`
template <class _Tp1, class _Tp2 = _Tp1>
using require_binary_divides =
    std::enable_if_t<std::is_convertible<decltype(std::declval<const _Tp1 &>() /
                                                  std::declval<const _Tp2 &>()),
                                         _Tp1>::value>;

template <class _Tp1, class _Tp2 = _Tp1, class = void>
struct has_binary_divides : std::false_type {};

template <class _Tp1, class _Tp2>
struct has_binary_divides<_Tp1, _Tp2, require_binary_divides<_Tp1, _Tp2>>
    : std::true_type {};

// Binary `%`
template <class _Tp1, class _Tp2 = _Tp1>
using require_binary_modulus =
    std::enable_if_t<std::is_convertible<decltype(std::declval<const _Tp1 &>() %
                                                  std::declval<const _Tp2 &>()),
                                         _Tp1>::value>;

template <class _Tp1, class _Tp2 = _Tp1, class = void>
struct has_binary_modulus : std::false_type {};

template <class _Tp1, class _Tp2>
struct has_binary_modulus<_Tp1, _Tp2, require_binary_modulus<_Tp1, _Tp2>>
    : std::true_type {};

template <class _Tp1, class _Tp2 = _Tp1, class = void, class = void,
          class = void, class = void>
struct has_arithmetic : std::false_type {};

template <class _Tp1, class _Tp2>
struct has_arithmetic<_Tp1, _Tp2, require_binary_plus<_Tp1, _Tp2>,
                      require_binary_minus<_Tp1, _Tp2>,
                      require_binary_multiplies<_Tp1, _Tp2>,
                      require_binary_divides<_Tp1, _Tp2>> : std::true_type {};

template <class _Tp1, class _Tp2 = _Tp1>
using require_arithmetic = std::enable_if_t<has_arithmetic<_Tp1, _Tp2>::value>;

// Binary `<`
template <class _Tp, class = void> struct is_comparable : std::false_type {};

template <class _Tp>
struct is_comparable<_Tp, std::__void_t<decltype(std::declval<const _Tp &>() <
                                                 std::declval<const _Tp &>())>>
    : std::true_type {};

template <class _Tp, bool _Default = false> struct try_less : std::less<_Tp> {
  constexpr bool operator()(const _Tp &__x, const _Tp &__y) noexcept {
    if _CXX17_CONSTEXPR (is_comparable<_Tp>::value)
      return std::less<_Tp>::operator()(__x, __y);
    else
      return _Default;
  }
};

}  // namespace workspace
#line 2 "src/utils/sfinae.hpp"

/**
 * @file sfinae.hpp
 * @brief SFINAE
 */

#include <cstdint>
#line 11 "src/utils/sfinae.hpp"

#ifndef __INT128_DEFINED__

#ifdef __SIZEOF_INT128__
#define __INT128_DEFINED__ 1
#else
#define __INT128_DEFINED__ 0
#endif

#endif

namespace std {

#if __INT128_DEFINED__

template <> struct make_signed<__uint128_t> { using type = __int128_t; };
template <> struct make_signed<__int128_t> { using type = __int128_t; };

template <> struct make_unsigned<__uint128_t> { using type = __uint128_t; };
template <> struct make_unsigned<__int128_t> { using type = __uint128_t; };

template <> struct is_signed<__uint128_t> : std::false_type {};
template <> struct is_signed<__int128_t> : std::true_type {};

template <> struct is_unsigned<__uint128_t> : std::true_type {};
template <> struct is_unsigned<__int128_t> : std::false_type {};

#endif

}  // namespace std

namespace workspace {

template <class Tp, class... Args> struct variadic_front { using type = Tp; };

template <class... Args> struct variadic_back;

template <class Tp> struct variadic_back<Tp> { using type = Tp; };

template <class Tp, class... Args> struct variadic_back<Tp, Args...> {
  using type = typename variadic_back<Args...>::type;
};

template <class type, template <class> class trait>
using enable_if_trait_type = typename std::enable_if<trait<type>::value>::type;

/**
 * @brief Return type of subscripting ( @c [] ) access.
 */
template <class _Tp>
using subscripted_type =
    typename std::decay<decltype(std::declval<_Tp&>()[0])>::type;

template <class Container>
using element_type = typename std::decay<decltype(*std::begin(
    std::declval<Container&>()))>::type;

template <class _Tp, class = void> struct has_begin : std::false_type {};

template <class _Tp>
struct has_begin<
    _Tp, std::__void_t<decltype(std::begin(std::declval<const _Tp&>()))>>
    : std::true_type {
  using type = decltype(std::begin(std::declval<const _Tp&>()));
};

template <class _Tp, class = void> struct has_size : std::false_type {};

template <class _Tp>
struct has_size<_Tp, std::__void_t<decltype(std::size(std::declval<_Tp>()))>>
    : std::true_type {};

template <class _Tp, class = void> struct has_resize : std::false_type {};

template <class _Tp>
struct has_resize<_Tp, std::__void_t<decltype(std::declval<_Tp>().resize(
                           std::declval<size_t>()))>> : std::true_type {};

template <class _Tp, class = void> struct has_mod : std::false_type {};

template <class _Tp>
struct has_mod<_Tp, std::__void_t<decltype(_Tp::mod)>> : std::true_type {};

template <class _Tp, class = void> struct is_integral_ext : std::false_type {};
template <class _Tp>
struct is_integral_ext<
    _Tp, typename std::enable_if<std::is_integral<_Tp>::value>::type>
    : std::true_type {};

#if __INT128_DEFINED__

template <> struct is_integral_ext<__int128_t> : std::true_type {};
template <> struct is_integral_ext<__uint128_t> : std::true_type {};

#endif

#if __cplusplus >= 201402

template <class _Tp>
constexpr static bool is_integral_ext_v = is_integral_ext<_Tp>::value;

#endif

template <typename _Tp, typename = void> struct multiplicable_uint {
  using type = uint_least32_t;
};
template <typename _Tp>
struct multiplicable_uint<
    _Tp,
    typename std::enable_if<(2 < sizeof(_Tp)) &&
                            (!__INT128_DEFINED__ || sizeof(_Tp) <= 4)>::type> {
  using type = uint_least64_t;
};

#if __INT128_DEFINED__

template <typename _Tp>
struct multiplicable_uint<_Tp,
                          typename std::enable_if<(4 < sizeof(_Tp))>::type> {
  using type = __uint128_t;
};

#endif

template <typename _Tp> struct multiplicable_int {
  using type =
      typename std::make_signed<typename multiplicable_uint<_Tp>::type>::type;
};

template <typename _Tp> struct multiplicable {
  using type = std::conditional_t<
      is_integral_ext<_Tp>::value,
      std::conditional_t<std::is_signed<_Tp>::value,
                         typename multiplicable_int<_Tp>::type,
                         typename multiplicable_uint<_Tp>::type>,
      _Tp>;
};

template <class> struct first_arg { using type = void; };

template <class _R, class _Tp, class... _Args>
struct first_arg<_R(_Tp, _Args...)> {
  using type = _Tp;
};

template <class _R, class _Tp, class... _Args>
struct first_arg<_R (*)(_Tp, _Args...)> {
  using type = _Tp;
};

template <class _G, class _R, class _Tp, class... _Args>
struct first_arg<_R (_G::*)(_Tp, _Args...)> {
  using type = _Tp;
};

template <class _G, class _R, class _Tp, class... _Args>
struct first_arg<_R (_G::*)(_Tp, _Args...) const> {
  using type = _Tp;
};

template <class _Tp, class = void> struct parse_compare : first_arg<_Tp> {};

template <class _Tp>
struct parse_compare<_Tp, std::__void_t<decltype(&_Tp::operator())>>
    : first_arg<decltype(&_Tp::operator())> {};

template <class _Container, class = void> struct get_dimension {
  static constexpr size_t value = 0;
};

template <class _Container>
struct get_dimension<_Container,
                     std::enable_if_t<has_begin<_Container>::value>> {
  static constexpr size_t value =
      1 + get_dimension<typename std::iterator_traits<
              typename has_begin<_Container>::type>::value_type>::value;
};

}  // namespace workspace
#line 2 "src/data_structure/segment_tree/waitings.hpp"

#line 5 "src/data_structure/segment_tree/waitings.hpp"

namespace workspace {

namespace internal {

struct waitings : std::queue<size_t> {
  waitings(size_t n) : in(n) {}

  bool push(size_t index) {
    // assert(index < in.size());
    if (in[index]) return false;
    emplace(index);
    return (in[index] = true);
  }

  size_t pop() {
    // assert(!empty());
    auto index = front();
    std::queue<size_t>::pop();
    in[index] = false;
    return index;
  }

 private:
  std::vector<int_least8_t> in;
};

}  // namespace internal

}  // namespace workspace
#line 16 "src/data_structure/segment_tree/lazy.hpp"

namespace workspace {

template <class _Monoid, class _End,
          class Monoid_container = std::vector<_Monoid>,
          class Endomorphism_container = std::vector<_End>>
class lazy_segment_tree {
  static_assert(
      std::is_same<_Monoid, typename Monoid_container::value_type>::value);

  static_assert(
      std::is_same<_End, typename Endomorphism_container::value_type>::value);

  static_assert(has_binary_plus<_Monoid>::value,
                "\'_Monoid\' has no proper binary \'operator+\'.");

  static_assert(has_binary_multiplies<_End>::value,
                "\'_End\' has no proper binary \'operator*\'.");

  static_assert(has_binary_multiplies<_Monoid, _End>::value,
                "\'_End\' is not applicable to \'_Monoid\'.");

  size_t size_orig, height, size_ext;
  Monoid_container data;
  Endomorphism_container lazy;
  internal::waitings wait;

  void repair() {
    while (!wait.empty()) {
      const size_t __i = wait.pop() >> 1;
      if (__i && wait.push(__i)) pull(__i);
    }
  }

  void _apply(size_t node, const _End &__e) {
    data[node] = data[node] * __e;
    if (node < size_ext) lazy[node] = lazy[node] * __e;
  }

  void push(size_t node) {
    _apply(node << 1, lazy[node]);
    _apply(node << 1 | 1, lazy[node]);
    lazy[node] = _End{};
  }

  void pull(size_t node) { data[node] = data[node << 1] + data[node << 1 | 1]; }

  template <class _Pred>
  size_t left_partition_subtree(size_t node, _Monoid mono, _Pred __pred) {
    assert(node);
    while (node < size_ext) {
      push(node);
      const _Monoid __tmp = data[(node <<= 1) | 1] + mono;
      if (__pred(__tmp))
        mono = std::move(__tmp);
      else
        ++node;
    }
    return ++node -= size_ext;
  }

  template <class _Pred>
  size_t right_partition_subtree(size_t node, _Monoid mono, _Pred __pred) {
    assert(node);
    while (node < size_ext) {
      push(node);
      const _Monoid __tmp = mono + data[node <<= 1];
      if (__pred(__tmp)) ++node, mono = std::move(__tmp);
    }
    return (node -= size_ext) < size_orig ? node : size_orig;
  }

 public:
  class iterator {
    lazy_segment_tree *__p;
    size_t __i;

   public:
    using difference_type = typename std::make_signed<size_t>::type;
    using value_type = _Monoid;
    using reference = _Monoid &;
    using pointer = iterator;
    using iterator_category = std::random_access_iterator_tag;

    /**
     * @brief Construct a new iterator object
     *
     */
    iterator() = default;

    /**
     * @brief Construct a new iterator object
     *
     * @param __p Pointer to a segment tree object
     * @param __i Index
     */
    iterator(lazy_segment_tree *__p, size_t __i) : __p(__p), __i(__i) {}

    bool operator==(iterator const &rhs) const {
      return __p == rhs.__p && __i == rhs.__i;
    }
    bool operator!=(iterator const &rhs) const { return !operator==(rhs); }

    bool operator<(iterator const &rhs) const { return __i < rhs.__i; }
    bool operator>(iterator const &rhs) const { return __i > rhs.__i; }
    bool operator<=(iterator const &rhs) const { return __i <= rhs.__i; }
    bool operator>=(iterator const &rhs) const { return __i >= rhs.__i; }

    iterator &operator++() { return ++__i, *this; }
    iterator &operator--() { return --__i, *this; }

    difference_type operator-(iterator const &rhs) const {
      return __i - rhs.__i;
    }

    /**
     * @brief
     *
     * @return reference
     */
    reference operator*() const { return __p->operator[](__i); }
  };

  using value_type = typename iterator::value_type;
  using reference = typename iterator::reference;

  iterator begin() { return {this, 0}; }
  iterator end() { return {this, size_orig}; }

  auto rbegin() { return std::make_reverse_iterator(end()); }
  auto rend() { return std::make_reverse_iterator(begin()); }

  lazy_segment_tree(size_t __n = 0)
      : size_orig{__n},
        height(__n > 1 ? 32 - __builtin_clz(__n - 1) : 0),
        size_ext{1u << height},
        data(size_ext << 1),
        lazy(size_ext),
        wait(size_ext << 1) {}

  lazy_segment_tree(size_t __n, const _Monoid &init) : lazy_segment_tree(__n) {
    std::fill_n(std::next(std::begin(data), size_ext), __n, init);
    for (size_t i{size_ext}; --i;) pull(i);
  }

  template <class iter_type, class value_type = typename std::iterator_traits<
                                 iter_type>::value_type>
  lazy_segment_tree(iter_type first, iter_type last)
      : size_orig(std::distance(first, last)),
        height(size_orig > 1 ? 32 - __builtin_clz(size_orig - 1) : 0),
        size_ext{1u << height},
        data(size_ext << 1),
        lazy(size_ext),
        wait(size_ext << 1) {
    static_assert(std::is_constructible<_Monoid, value_type>::value,
                  "_Monoid(iter_type::value_type) is not constructible.");
    for (auto iter{std::next(std::begin(data), size_ext)};
         iter != std::end(data) && first != last; ++iter, ++first)
      *iter = _Monoid(*first);
    for (size_t i{size_ext}; --i;) pull(i);
  }

  /**
   * @return Number of elements.
   */
  size_t size() const { return size_orig; }

  /**
   * @param __i Index of the element
   * @return Reference to the element.
   */
  _Monoid &operator[](size_t __i) {
    assert(__i < size_orig);
    __i |= size_ext;
    wait.push(__i);
    for (size_t i = height; i; --i) push(__i >> i);
    return data[__i];
  }

  void apply(const _End &__e) { apply(0, size_orig, __e); }

  void apply(size_t __i, const _End &__e) { apply(__i, __i + 1, __e); }

  void apply(size_t first, size_t last, const _End &__e) {
    assert(last <= size_orig);
    repair();
    if (first >= last) return;
    first += size_ext, last += size_ext;
    --last;
    for (size_t i = height; i; --i) push(first >> i), push(last >> i);
    ++last;
    for (size_t l = first, r = last; l != r; l >>= 1, r >>= 1) {
      if (l & 1) _apply(l++, __e);
      if (r & 1) _apply(--r, __e);
    }
    for (first >>= __builtin_ffs(first); first; first >>= 1) pull(first);
    for (last >>= __builtin_ffs(last); last; last >>= 1) pull(last);
  }

  /**
   * @param first Left end, inclusive
   * @param last Right end, exclusive
   * @return Sum of elements in the interval.
   */
  _Monoid fold(size_t first, size_t last) {
    assert(last <= size_orig);
    repair();
    if (first >= last) return _Monoid{};
    first += size_ext, last += size_ext - 1;
    _Monoid left_val{}, right_val{};
    for (size_t l = first, r = last + 1; l != r; l >>= 1, r >>= 1) {
      if (l & 1) left_val = left_val + data[l++];
      if (r & 1) right_val = data[--r] + right_val;
      left_val = left_val * lazy[first >>= 1];
      right_val = right_val * lazy[last >>= 1];
    }
    while (first >>= 1, last >>= 1) {
      left_val = left_val * lazy[first];
      right_val = right_val * lazy[last];
    }
    return left_val + right_val;
  }

  /**
   * @return Sum of all elements.
   */
  _Monoid fold() {
    repair();
    return data[1];
  }

  /**
   * @brief Binary search for the partition point.
   * @param __r Right fixed end of the interval, exclusive
   * @param __pred Predicate in the form of 'bool(_Monoid)'
   * @return Left end of the extremal interval satisfying the condition,
   * inclusive.
   */
  template <class _Pred> size_t left_partition(size_t __r, _Pred __pred) {
    assert(__r <= size_orig);
    repair();
    __r += size_ext - 1;
    for (size_t i{height}; i; --i) push(__r >> i);
    ++__r;
    _Monoid mono{};
    for (size_t __l{size_ext}, step{}; __l != __r;
         __l >>= 1, __r >>= 1, ++step) {
      if ((__l & 1) != (__r & 1)) {
        const _Monoid __tmp = data[--__r] + mono;
        if (!__pred(__tmp))
          return left_partition_subtree(__r, std::move(mono), __pred);
        mono = std::move(__tmp);
      }
    }
    return 0;
  }

  /**
   * @brief Binary search for the partition point.
   * @param __l Left fixed end of the interval, inclusive
   * @param __pred Predicate in the form of 'bool(_Monoid)'
   * @return Right end of the extremal interval satisfying the condition,
   * exclusive.
   */
  template <class _Pred> size_t right_partition(size_t __l, _Pred __pred) {
    assert(__l <= size_orig);
    repair();
    __l += size_ext;
    for (size_t i{height}; i; --i) push(__l >> i);
    _Monoid mono{};
    for (size_t __r{size_ext << 1}, step{}; __l != __r;
         __l >>= 1, __r >>= 1, ++step) {
      if ((__l & 1) != (__r & 1)) {
        const _Monoid __tmp = mono + data[__l];
        if (!__pred(__tmp))
          return right_partition_subtree(__l, std::move(mono), __pred);
        mono = std::move(__tmp);
        ++__l;
      }
    }
    return size_orig;
  }
};

}  // namespace workspace
Back to top page