69# ifndef TPL_LINK_CUT_TREE_H
70# define TPL_LINK_CUT_TREE_H
73# include <initializer_list>
76# include <type_traits>
95 template <
typename M,
typename T>
97 requires(
const M &
m,
const T & a,
const T & b)
99 { M::identity() } -> std::convertible_to<T>;
100 { M::combine(a, b) } -> std::convertible_to<T>;
109 template <
typename L,
typename T>
111 std::equality_comparable<typename L::tag_type>
and
112 requires(
const typename L::tag_type &
t1,
113 const typename L::tag_type &
t2,
114 const T & val,
size_t cnt)
116 typename L::tag_type;
117 { L::tag_identity() } -> std::convertible_to<typename L::tag_type>;
118 { L::apply(val,
t1, cnt) } -> std::convertible_to<T>;
119 { L::compose(
t1,
t2) } -> std::convertible_to<typename L::tag_type>;
127 template <
typename T>
131 static constexpr T combine(
const T &,
const T & b)
noexcept {
return b; }
135 template <
typename T>
142 static constexpr T combine(
const T & a,
const T & b)
noexcept
149 template <
typename T>
154 return std::numeric_limits<T>::max();
157 static constexpr T combine(
const T & a,
const T & b)
noexcept
159 return a < b ? a : b;
164 template <
typename T>
169 return std::numeric_limits<T>::lowest();
172 static constexpr T combine(
const T & a,
const T & b)
noexcept
174 return a > b ? a : b;
179 template <
typename T>
184 static constexpr T combine(
const T & a,
const T & b)
noexcept
191 template <
typename T>
196 static constexpr T combine(
const T & a,
const T & b)
noexcept
198 T x = a <
T{0} ? -a : a;
199 T y = b <
T{0} ? -b : b;
211 template <
typename T>
216 static constexpr T combine(
const T & a,
const T & b)
noexcept
227 template <
typename T>
232 static constexpr T apply(
const T & v,
bool,
size_t)
noexcept {
return v; }
233 static constexpr bool compose(
bool,
bool)
noexcept {
return false; }
242 template <
typename T>
248 static constexpr T apply(
const T & v,
const T & tag,
size_t cnt)
noexcept
250 return v + tag *
static_cast<T>(cnt);
253 static constexpr T compose(
const T & a,
const T & b)
noexcept
268 template <
typename T>
288 return tag.active ? tag.val *
static_cast<T>(cnt) : v;
299 template <
class Mono
id,
class =
void>
303 template <
class Mono
id>
305 : std::bool_constant<Monoid::supports_counted_lazy::value> {};
308 template <
class LazyTag,
typename T>
312 template <
typename T>
316 template <
typename T>
357 template <
typename T =
int,
365 "AddLazyTag::apply and AssignLazyTag::apply require a monoid "
366 "with supports_counted_lazy=true");
405 return x->parent ==
nullptr or
406 (x->parent->left != x
and x->parent->right != x);
411 return x->parent
and x->parent->left == x;
423 std::swap(x->left, x->right);
424 if (x->left) x->left->rev ^=
true;
425 if (x->right) x->right->rev ^=
true;
429 if constexpr (
not std::is_same_v<LazyTag, NoLazyTag<T>>)
431 if (
not (x->lazy == LazyTag::tag_identity()))
437 c->val = LazyTag::apply(c->val, x->lazy, 1);
438 c->agg = LazyTag::apply(c->agg, x->lazy, c->sz);
439 c->lazy = LazyTag::compose(c->lazy, x->lazy);
443 x->lazy = LazyTag::tag_identity();
460 x->sz += x->left->sz;
461 x->agg = Monoid::combine(x->left->agg, x->agg);
465 x->sz += x->right->sz;
466 x->agg = Monoid::combine(x->agg, x->right->agg);
522 while (
not stk.is_empty())
547 Node *last =
nullptr;
548 for (
Node *u = x; u !=
nullptr; u = u->
parent)
561 template <
typename Op>
587 for (
size_t i = 0; i <
nodes.
size(); ++i)
627 auto *
nd =
new Node(std::move(val));
647 <<
"vertex does not belong to this link-cut tree";
651 <<
"vertex must be isolated";
700 if (x->
left ==
nullptr)
775 <<
"edge does not exist";
892 requires (
not std::is_same_v<LazyTag, NoLazyTag<T>>)
898 v->val = LazyTag::apply(v->val, tag, 1);
899 v->agg = LazyTag::apply(v->agg, tag, v->sz);
900 v->lazy = LazyTag::compose(v->lazy, tag);
921 for (
size_t i = 0; i <
nodes.
size(); ++i)
964 template <
typename Op>
967 for (
size_t i = 0; i <
nodes.
size(); ++i)
976 template <
typename Op>
987 for (
size_t i =
rev_path.size(); i > 0; --i)
1007 Node *prev =
nullptr;
1008 for (
const auto & v:
vals)
1026 for (
const auto & v:
vals)
1035 template <
typename Container>
1038 for (
const auto & [u, v]: edges)
1078 for (
size_t i = 0; i <
tree_nodes.size(); ++i)
1083 for (
size_t i = 0; i <
lct_nodes.size(); ++i)
1092 void operator()(
TN *
nd)
const noexcept
1101 for (
size_t i = 0; i <
lct_nodes.size(); ++i)
1109 std::unique_ptr<TN> child(
new TN(
lct_nodes(i)->val));
1110 tree_nodes(pi)->insert_rightmost_child(child.get());
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
void destroy_tree(Tree &tree)
WeightedDigraph::Node Node
Stack implemented with simple dynamic array and with bounds verification.
T & push(const T &data)
Push into stack a copy of data
Simple dynamic array with automatic resizing and functional operations.
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
T & append(const T &data)
Append a copy of data
Dynamic forest with path queries via Link-Cut Trees.
Gen_Link_Cut_Tree()=default
Default constructor for an empty Link-Cut Tree.
void set_val(Node *x, const T &val)
Update the payload value of vertex x and recompute aggregates.
size_t path_size(Node *u, Node *v)
Number of vertices on the path from u to v.
void destroy_vertex(Node *x)
Destroy an isolated vertex.
const T & get_val(Node *x)
Read the payload value of vertex x.
void make_root(Node *x)
Make x the root of its represented tree.
size_t tree_size(Node *x)
Number of vertices in the tree containing x.
void path_apply(Node *u, Node *v, const typename LazyTag::tag_type &tag)
Apply a lazy tag to every vertex on the path from u to v.
Tree_Node< T > * export_to_tree_node(Node *root)
Export the represented tree rooted at root as a Tree_Node<T>.
T path_query(Node *u, Node *v)
Aggregate (under Monoid) over all vertex values on the path from u to v.
size_t depth(Node *x)
Depth of x relative to the current root of its tree.
Node * find_root(Node *x)
Find the root of the represented tree containing x.
Gen_Link_Cut_Tree(Gen_Link_Cut_Tree &&)=delete
Deleted move constructor.
void for_each_node(Op &&op) const
Call op(Node *) for every vertex in the forest.
Gen_Link_Cut_Tree & operator=(const Gen_Link_Cut_Tree &)=delete
Deleted copy assignment.
size_t num_components() const noexcept
Number of connected components (trees) in the forest.
Node * parent(Node *x)
Parent of x in the represented tree under the current rooting.
Gen_Link_Cut_Tree(const Gen_Link_Cut_Tree &)=delete
Deleted copy constructor.
~Gen_Link_Cut_Tree()
Destructor.
Node * make_vertex(T &&val)
Create an isolated vertex (move semantics).
static void push(Node *x) noexcept
static Node * access(Node *x) noexcept
bool connected(Node *u, Node *v)
Test whether u and v are in the same represented tree.
void for_each_on_path(Node *u, Node *v, Op &&op)
Call op(Node *) for every vertex on the path from u to v, in order from u to v.
Node * make_vertex(const T &val=T{})
Create an isolated vertex with payload val.
static void rotate(Node *x) noexcept
Gen_Link_Cut_Tree & operator=(Gen_Link_Cut_Tree &&)=delete
Deleted move assignment.
void link_edges(const Container &edges)
Link every pair in an edge container.
Array< Node * > make_vertices(std::initializer_list< T > vals)
Create isolated vertices from an initializer list of values.
void link(Node *u, Node *v)
Add an edge between u and v, merging their trees.
static bool is_root(const Node *x) noexcept
static void inorder_traverse(Node *root, Op &&op)
static bool is_left(const Node *x) noexcept
static void pull(Node *x) noexcept
size_t size() const noexcept
Total number of vertices currently in the forest.
Node * lca(Node *u, Node *v)
Lowest common ancestor of u and v.
void cut(Node *u, Node *v)
Remove the represented edge between u and v.
Array< Node * > make_path(std::initializer_list< T > vals)
Create a path of vertices from an initializer list of values.
static void splay(Node *x) noexcept
Concept for a lazy-tag policy used in deferred path updates.
Concept for a monoidal combiner over path values.
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Main namespace for Aleph-w library functions.
and
Check uniqueness with explicit hash + equality functors.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::decay_t< typename HeadC::Item_Type > T
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Additive lazy tag: adds a delta to every node on a path.
static constexpr T apply(const T &v, const T &tag, size_t cnt) noexcept
static constexpr T compose(const T &a, const T &b) noexcept
static constexpr T tag_identity() noexcept
Payload for the assignment lazy tag.
constexpr bool operator==(const tag_type &o) const noexcept
Assignment lazy tag: sets every node on a path to a fixed value.
static constexpr T apply(const T &v, const tag_type &tag, size_t cnt) noexcept
static constexpr tag_type compose(const tag_type &existing, const tag_type &newer) noexcept
static constexpr tag_type tag_identity() noexcept
Default (no-op) monoid for connectivity-only usage.
static constexpr T identity() noexcept
static constexpr T combine(const T &, const T &b) noexcept
GCD monoid: identity = 0 (since gcd(0, x) = x), combine = gcd.
static constexpr T combine(const T &a, const T &b) noexcept
static constexpr T identity() noexcept
Internal node of the Link-Cut Tree (opaque handle).
typename LazyTag::tag_type tag_type
const T & get_val() const noexcept
Return the raw stored value without forcing synchronization.
Max monoid: identity = numeric lowest, combine = max(a, b).
static constexpr T identity() noexcept
static constexpr T combine(const T &a, const T &b) noexcept
Min monoid: identity = numeric max, combine = min(a, b).
static constexpr T combine(const T &a, const T &b) noexcept
static constexpr T identity() noexcept
No-op lazy tag (default — no deferred path updates).
static constexpr bool tag_identity() noexcept
static constexpr T apply(const T &v, bool, size_t) noexcept
static constexpr bool compose(bool, bool) noexcept
Product monoid: identity = 1, combine = a * b.
static constexpr T combine(const T &a, const T &b) noexcept
static constexpr T identity() noexcept
Sum monoid: identity = 0, combine = a + b.
static constexpr T combine(const T &a, const T &b) noexcept
std::true_type supports_counted_lazy
static constexpr T identity() noexcept
XOR monoid: identity = 0, combine = a ^ b.
static constexpr T identity() noexcept
static constexpr T combine(const T &a, const T &b) noexcept
Metafunction to check if a tag is a counted lazy tag.
Metafunction to check if a monoid supports counted lazy tags.
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
Stack implementations backed by dynamic or fixed arrays.
Dynamic array container with automatic resizing.
General tree (n-ary tree) node.