【线段树的可持久化】(主席树 | 历史记录 | 版本回溯)

 

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)); }

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XNB's Not a Beginner

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值