class uninitialized : public std::exception {
public:
virtual char const * what() const noexcept override {
return "try to visit element before initialize";
}
};
/**
* @brief user-defined exception
* @code: 未初始化的情况下访问线段树的元素
**/
class repeated_assign : public std::exception {
public:
virtual char const * what() const noexcept override {
return "try to assign repeatedly";
}
};
/**
* @brief user-defined exception
* @code 重复未线段树赋值
**/
template <typename Tp, typename Fn>
requires std::is_default_constructible<Tp>::value
&& std::invocable<Fn, Tp, Tp>
&& std::convertible_to<typename std::invoke_result<Fn, Tp, Tp>::type, Tp>
&& std::assignable_from<Tp, Tp const &>
&& std::constructible_from<Tp, Tp const &>
&& requires { std::equal_to<Tp> {}; }
/**
* @brief template argument requirements
* [可赋值/拷贝、满足区间加法、可调用对象良构、可比较]
**/
class segment_tree {
public: static constexpr auto CAPACITY_LIMIT { static_cast<int>(1 << 16) };
static constexpr auto ITERATION_LIMIT { static_cast<int>(1 << 8) };
private:
std::array<int, CAPACITY_LIMIT + 1> origin {};
std::array<int, CAPACITY_LIMIT << 1 | 1> trait {};
std::array<int, CAPACITY_LIMIT << 1 | 1> counter {};
std::array<int, CAPACITY_LIMIT << 1 | 1> left {};
std::array<int, CAPACITY_LIMIT << 1 | 1> right {};
std::array<int, ITERATION_LIMIT> root {};
Fn f;
std::size_t size {0u};
int generation {0};
int iteration {0};
private:
void update(int index) noexcept {
trait[index] = std::invoke(f, trait[left[index]], trait[right[index]]);
if(std::equal_to<>{} (trait[left[index]], trait[right[index]]))
counter[index] = std::plus<>{} (counter[left[index]], counter[right[index]]);
else
counter[index] = std::equal_to<>{} (trait[index], trait[right[index]]) ?
counter[left[index]] :
counter[right[index]];
}
constexpr void initialize() noexcept {
root.fill(-1);
left.fill(-1);
right.fill(-1);
}
void modify(int position, int value, int first, int last, int & index, int recent) noexcept {
if(! ~index) index = generation ++;
if(first + 1 == last) return (void) trait[index] = value;
int middle { (first + last) / 2 };
if(position < last) {
right[index] = right[recent];
modify(position, value, first, middle, left[index], left[recent]);
}else {
left[index] = left[recent];
modify(position, value, middle, last, right[index], right[recent]);
}
update(index);
}
void build(int first, int last, int & index) noexcept {
if(! ~index) index = generation ++;
if(first + 1 == last) return (void) (trait[index] = origin[first] && counter[index] = 1);
int middle { (first + last) / 2 };
build(first, middle, left[index]);
build(middle, last, right[index]);
update(index);
}
std::pair<Tp, std::size_t> query(int first, int last, int it_first, int it_last, int index) {
if(! ~index) throw std::runtime_error("default to query");
if(first <= it_first && it_last <= last) return {trait[index], counter[index]};
int middle { (it_first + it_last) / 2 };
if(first < middle && last > middle ) {
auto [left_trait, left_counter] = query(first, last, it_first, middle, left[index]);
auto [right_trait, right_counter] = query(first, last, middle, it_last, right[index]);
auto result_trait { std::invoke(f, left_trait, right_trait) };
if(std::equal_to<>{} (right_trait, left_trait)) return {result_trait, left_counter + right_counter};
if(std::equal_to<>{} (result_trait, left_trait)) return {result_trait, left_counter};
return {result_trait, right_counter};
}
if(first < middle)
return {trait[left[index]], counter[left[index]]};
if(last > middle)
return {trait[right[index]], counter[right[index]]};
}
void boundary_check(int position) {
if(position < 0 || position >= static_cast<int>(size))
throw std::out_of_range {};
}
void segment_check(int first, int last) {
boundary_check(first);
boundary_check(last);
if(first > last)
throw std::invalid_argument("range: [first, last) is invalid");
}
void iteration_check(int it) {
if(it < 0 || it > iteration)
throw std::invalid_argument("iteration out of range");
}
public:
constexpr segment_tree() noexcept { initialize(); };
segment_tree(segment_tree const &) = default;
segment_tree& operator=(segment_tree const &) = default;
segment_tree(segment_tree &&) noexcept = default;
segment_tree& operator=(segment_tree &&) noexcept = default;
template <typename Callable>
segment_tree(Callable&& __f) : f(std::forward<Callable>(__f)) { initialize(); }
template <typename Callable, typename Up, typename... Us>
requires (std::same_as<Up, Us>&& ...)
segment_tree(Callable&& __f, Up one, Us ...rem)
: f(std::forward<Callable>(__f))
, origin(one, rem ...)
, size(sizeof...(Us) + 1){
initialize();
build(0, static_cast<int>(size), root[iteration]);
}
void assign(std::initializer_list<Tp> ilist) {
if(generation) throw repeated_assign {};
for(auto i {0u}; i < ilist.size(); ++i)
origin[i] = ilist[i];
size = ilist.size();
build(0, static_cast<int>(size), root[iteration]);
}
void modify(int position, Tp const & value) {
boundary_check(position);
if(! generation) throw uninitialized {};
++ iteration;
origin[position] = value;
return (void) modify(position, value, 0, static_cast<int>(size), root[iteration], root[iteration - 1]);
}
Tp const & origin_at(std::size_t index) const {
if(! generation) throw uninitialized {};
return origin.at(index);
}
std::pair<Tp, std::size_t> query(int it, int first, int last) {
iteration_check(it);
segment_check(first, last);
return query(first, last, 0, static_cast<int>(size), root[it]);
}
};
template <typename Callable>
segment_tree(Callable&&)
-> segment_tree<
typename function_traits<typename std::decay<Callable>::type>::return_type,
typename std::decay<Callable>::type
>;
template <typename Callable, typename Up, typename... Us>
segment_tree(Callable&&, Up, Us ...)
-> segment_tree<
Up,
typename std::decay<Callable>::type
>;
/*
* type F meets std::invocable concept requires
* F(SomeArgs ...) -> SomeRet
*/
template <typename F> struct function_traits;
/*
* primitive function type that meets std::is_function requires
* Ret(Args ...) [const] [volatile] [&/&&] [noexcept]
*/
template <typename Ret, typename... Args>
struct function_traits<Ret(Args ...)> {
static constexpr std::size_t Arity { sizeof...(Args) };
using return_type = Ret;
using function_type = Ret(Args ...);
using callable_wrapper_type = std::function<Ret(Args ...)>;
typedef Ret(*function_pointer_type)(Args ...);
template <std::size_t I> struct args{
static_assert(I < Arity, "index out of range");
using type = typename std::tuple_element<I, std::tuple<Args...>>::type;
};
using fundamental_tuple_type = std::tuple<std::decay_t<Args>...>;
using original_tuple_type = std::tuple<std::remove_cv_t<Args> ...>;
};
/*
* pointers to functions
*/
template <typename Ret, typename ...Args>
struct function_traits<Ret(*)(Args ...)> : function_traits<Ret(Args ...)> {};
/*
* std::function with primitive function wrapped within bebind
*/
template <typename Ret, typename ...Args>
struct function_traits<std::function<Ret(Args ...)>> : function_traits<Ret(Args ...)> {};
/*
* member function ptr
* convertible from std::mem_ptr
*/
#define FUNCTION_TRAITS(...)\
template <typename Ret, typename Class, typename... Args>\
struct function_traits<Ret(Class::*)(Args ...) __VA_ARGS__> : function_traits<Ret(Args ...)> {};
FUNCTION_TRAITS()
FUNCTION_TRAITS(const)
FUNCTION_TRAITS(volatile)
FUNCTION_TRAITS(const volatile)
/*
* classes with overloaded operator()
* with lambda included
*/
template <typename Functor>
struct function_traits : function_traits<decltype(Functor::operator())> {};
/*
* from any function object to std::function
* use function_traits purification
*/
template <typename F>
auto to_function(F const & lambda)
{ return static_cast<typename function_traits<F>::callable_wrapper_type>(lambda); }
template <typename F>
auto to_function(F && lambda)
{ return static_cast<typename function_traits<F>::callable_wrapper_type>(std::forward<F>(lambda)); }