111# ifndef TREE_DECOMPOSITION_H
112# define TREE_DECOMPOSITION_H
118# include <type_traits>
132 namespace tree_decomposition_detail
151 template <
class GT,
class SA>
158 static constexpr size_t NONE = std::numeric_limits<size_t>::max();
178 return std::make_pair(u, v);
184 <<
where <<
": id=" <<
id <<
" is out of range [0, " <<
n_ <<
")";
194 <<
"Rooted_Tree_Topology: root node provided but graph is empty";
206 Node *p = it.get_curr();
213 <<
"Rooted_Tree_Topology: failed to index all graph nodes";
215 if (
root_ ==
nullptr)
219 <<
"Rooted_Tree_Topology: root node does not belong to graph";
231 for (
size_t i = 0; i <
n_; ++i)
239 Arc *a = it.get_curr_ne();
247 <<
"Rooted_Tree_Topology: arc endpoint is not indexed";
253 <<
"Rooted_Tree_Topology: self-loop detected in filtered graph";
257 <<
"Rooted_Tree_Topology: parallel/duplicate edge detected in filtered graph";
264 <<
"Rooted_Tree_Topology: filtered graph is not a tree (expected "
268 it.has_curr(); it.next_ne())
270 const auto & [
fst,
snd] = it.get_curr();
273 const size_t u =
fst.first;
274 const size_t v =
fst.second;
286 for (
size_t i = 0; i <
n_; ++i)
303 auto &
fr = stack.
top();
312 if (
nxt ==
fr.parent)
316 <<
"Rooted_Tree_Topology: filtered graph is not acyclic";
324 <<
"Rooted_Tree_Topology: filtered graph is not connected";
354 <<
"Rooted_Tree_Topology::id_of: null node";
358 <<
"Rooted_Tree_Topology::id_of: node does not belong to graph";
365 check_id(
id,
"Rooted_Tree_Topology::node_of");
391 template <
class GT,
class SA = Dft_Show_Arc<GT>>
419 const size_t n =
size();
431 for (
size_t i = 0; i < n; ++i)
443 for (
size_t i = 0; i < n; ++i)
469 auto &
fr = stack.
top();
478 if (
nxt ==
fr.parent)
482 <<
"Gen_Heavy_Light_Decomposition: filtered graph is not acyclic";
495 <<
"Gen_Heavy_Light_Decomposition: filtered graph is not connected";
497 for (
size_t i = order.
size(); i-- > 0;)
499 const size_t u = order(i);
526 head_(u) = chain_head;
540 <<
"Gen_Heavy_Light_Decomposition: invalid decomposition size";
551 : topology_(g,
root,
std::move(sa))
553 build_decomposition();
564 build_decomposition();
575 return topology_.node_of(
id);
580 return topology_.id_of(node);
585 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::parent_id");
591 const size_t pid = parent_id(id_of(node));
592 return pid == NONE ?
nullptr : node_of(pid);
597 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::depth_of_id");
603 return depth_of_id(id_of(node));
608 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::subtree_size_of_id");
609 return subtree_size_(
id);
614 return subtree_size_of_id(id_of(node));
619 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::heavy_child_id");
625 const size_t cid = heavy_child_id(id_of(node));
631 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::head_id");
637 return node_of(head_id(id_of(node)));
642 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::position_of_id");
648 return position_of_id(id_of(node));
654 topology_.validate_id(
id,
"Gen_Heavy_Light_Decomposition::subtree_range_id");
655 const size_t l = pos_(
id);
656 const size_t r =
l + subtree_size_(
id) - 1;
663 return subtree_range_id(id_of(node));
669 const Range r = subtree_range_id(u);
670 const size_t pv = position_of_id(v);
677 return is_ancestor_id(id_of(u), id_of(v));
683 ensure_not_empty(
"Gen_Heavy_Light_Decomposition::lca_id");
684 topology_.validate_id(u,
"Gen_Heavy_Light_Decomposition::lca_id");
685 topology_.validate_id(v,
"Gen_Heavy_Light_Decomposition::lca_id");
687 while (head_(u) != head_(v))
688 if (depth_(head_(u)) >= depth_(head_(v)))
689 u = parent_(head_(u));
691 v = parent_(head_(v));
693 return (depth_(u) <= depth_(v)) ? u : v;
699 return node_of(lca_id(id_of(u), id_of(v)));
705 const size_t a = lca_id(u, v);
706 return depth_(u) + depth_(v) - 2 * depth_(a);
712 return distance_id(id_of(u), id_of(v));
728 ensure_not_empty(
"Gen_Heavy_Light_Decomposition::for_each_path_segment_id");
729 topology_.validate_id(u,
"Gen_Heavy_Light_Decomposition::for_each_path_segment_id");
730 topology_.validate_id(v,
"Gen_Heavy_Light_Decomposition::for_each_path_segment_id");
734 while (head_(u) != head_(v))
735 if (depth_(head_(u)) >= depth_(head_(v)))
737 visit(pos_(head_(u)), pos_(u),
true);
738 u = parent_(head_(u));
743 v = parent_(head_(v));
746 if (depth_(u) >= depth_(v))
747 visit(pos_(v), pos_(u),
true);
754 visit(left, right,
false);
762 for_each_path_segment_id(id_of(u), id_of(v), std::forward<F>(
visit));
774 for_each_path_segment_id(u, v,
775 [&](
const size_t l,
const size_t r,
const bool)
827 template <
class Getter>
828 requires std::invocable<Getter, Node *>
and
829 std::convertible_to<std::invoke_result_t<Getter, Node *>,
T>
833 const size_t n =
hld.size();
838 for (
size_t id = 0;
id < n; ++id)
840 const size_t p =
hld.position_of_id(
id);
841 base(p) =
static_cast<T>(
getter(
hld.node_of(
id)));
852 return static_cast<T>(p->get_info());
885 template <
class Getter>
886 requires std::invocable<Getter, Node *>
and
887 std::convertible_to<std::invoke_result_t<Getter, Node *>,
T>
903 template <
class Getter>
904 requires std::invocable<Getter, Node *>
and
905 std::convertible_to<std::invoke_result_t<Getter, Node *>,
T>
933 hld_.for_each_path_segment_id(u, v,
953 const auto range =
hld_.subtree_range_id(
id);
1022 template <
class GT,
class SA = Dft_Show_Arc<GT>>
1055 const size_t n =
size();
1064 for (
size_t i = 0; i < n; ++i)
1088 const size_t u = stack.
pop();
1112 <<
"Gen_Centroid_Decomposition: empty component while choosing centroid";
1114 for (
size_t i =
total; i-- > 0;)
1116 const size_t u =
nodes(i);
1130 size_t centroid =
nodes(0);
1133 for (
size_t i = 0; i <
total; ++i)
1135 const size_t u =
nodes(i);
1182 stack.
push({v,
fr.node,
fr.dist + 1});
1189 const size_t n =
size();
1228 tasks.
push({v, centroid,
task.level + 1});
1232 <<
"Gen_Centroid_Decomposition: invalid centroid tree size";
1238 : topology_(g,
root,
std::move(sa))
1240 build_centroid_tree();
1247 build_centroid_tree();
1258 return topology_.node_of(
id);
1263 return topology_.id_of(node);
1269 return centroid_root_;
1275 return centroid_root_ == NONE ?
nullptr : node_of(centroid_root_);
1281 topology_.validate_id(
id,
"Gen_Centroid_Decomposition::centroid_parent_id");
1282 return centroid_parent_(
id);
1288 const size_t pid = centroid_parent_id(id_of(node));
1289 return pid == NONE ?
nullptr : node_of(pid);
1295 topology_.validate_id(
id,
"Gen_Centroid_Decomposition::centroid_level_of_id");
1296 return centroid_level_(
id);
1302 return centroid_level_of_id(id_of(node));
1309 for (
size_t i = 0; i <
size(); ++i)
1310 ret = std::max(
ret, centroid_level_(i));
1317 topology_.validate_id(
id,
"Gen_Centroid_Decomposition::centroid_path_length_of_id");
1318 return centroid_ancestors_(
id).size();
1324 return centroid_path_length_of_id(id_of(node));
1330 topology_.validate_id(
id,
"Gen_Centroid_Decomposition::centroid_ancestors_of_id");
1331 return centroid_ancestors_(
id);
1337 topology_.validate_id(
id,
"Gen_Centroid_Decomposition::centroid_distances_of_id");
1338 return centroid_distances_(
id);
1344 return centroid_ancestors_of_id(id_of(node));
1350 return centroid_distances_of_id(id_of(node));
1355 const size_t node)
const
1357 topology_.validate_id(
ancestor,
"Gen_Centroid_Decomposition::is_centroid_ancestor_id");
1358 topology_.validate_id(node,
"Gen_Centroid_Decomposition::is_centroid_ancestor_id");
1360 const auto &
chain = centroid_ancestors_(node);
1361 for (
size_t i = 0; i <
chain.size(); ++i)
1373 const size_t centroid)
const
1375 topology_.validate_id(node,
"Gen_Centroid_Decomposition::distance_to_centroid_id");
1376 topology_.validate_id(centroid,
"Gen_Centroid_Decomposition::distance_to_centroid_id");
1378 const auto &
chain = centroid_ancestors_(node);
1379 const auto &
dists = centroid_distances_(node);
1381 for (
size_t i = 0; i <
chain.size(); ++i)
1382 if (
chain(i) == centroid)
1395 ensure_not_empty(
"Gen_Centroid_Decomposition::for_each_centroid_ancestor_id");
1396 topology_.validate_id(node,
"Gen_Centroid_Decomposition::for_each_centroid_ancestor_id");
1398 const auto &
chain = centroid_ancestors_(node);
1399 const auto &
dists = centroid_distances_(node);
1402 <<
"Gen_Centroid_Decomposition: invalid centroid annotation state";
1404 for (
size_t i = 0; i <
chain.size(); ++i)
1415 for_each_centroid_ancestor_id(id_of(node), std::forward<F>(f));
1421 template <
class GT,
class SA = Dft_Show_Arc<GT>>
1432 template <
class GT,
class SA = Dft_Show_Arc<GT>>
Exception handling system with formatted messages for Aleph-w.
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
#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.
Standard functor implementations and comparison objects.
List_Graph< Graph_Node< Node_Info >, Graph_Arc< Arc_Info > > GT
Simple dynamic array with automatic resizing and functional operations.
static Array create(size_t n)
Create an array with n logical elements.
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
void reserve(size_t cap)
Reserves cap cells into the array.
Dynamic stack of elements of generic type T based on a singly linked list.
T & top()
Return a modifiable reference to the top item of the stack.
bool is_empty() const noexcept
Check if the stack is empty.
T pop()
Remove and return the top item of the stack.
T & push(const T &data)
Push an item by copy onto the top of the stack.
Generic key-value map implemented on top of a binary search tree.
typename Base::Iterator Iterator
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
Centroid decomposition over a rooted tree represented as an Aleph graph.
Node * centroid_parent(const Node *node) const
Parent centroid of node (or nullptr if centroid root).
size_t centroid_path_length_of(const Node *node) const
Number of centroid ancestors stored for node.
Array< size_t > centroid_parent_
Array< size_t > centroid_level_
Array< Array< size_t > > centroid_distances_
bool is_empty() const noexcept
size_t centroid_level_of_id(const size_t id) const
Level of centroid id in centroid tree (root level = 0).
void build_centroid_tree()
const Array< size_t > & centroid_ancestors_of(const Node *node) const
Centroid ancestors of node from centroid root down to local centroid.
Node * centroid_root() const noexcept
Root centroid node of the centroid tree (or nullptr if empty).
bool is_centroid_ancestor_id(const size_t ancestor, const size_t node) const
True iff ancestor is in the centroid-ancestor chain of node.
void ensure_not_empty(const char *where) const
size_t centroid_level_of(const Node *node) const
Level of centroid node in centroid tree (root level = 0).
size_t centroid_root_id() const noexcept
Root centroid ID of the centroid tree (or NONE if empty).
Gen_Centroid_Decomposition(const GT &g, Node *root, SA sa=SA())
Construct using an explicit root node.
const Array< size_t > & centroid_ancestors_of_id(const size_t id) const
Centroid ancestors of node ID from centroid root down to local centroid.
Node * node_of(const size_t id) const
Array< size_t > local_subtree_
size_t centroid_parent_id(const size_t id) const
Parent centroid ID of id (or NONE if centroid root).
size_t centroid_path_length_of_id(const size_t id) const
Number of centroid ancestors stored for node ID.
const Array< size_t > & centroid_distances_of(const Node *node) const
Distances to centroid ancestors (aligned with centroid_ancestors_of).
size_t max_centroid_level() const noexcept
Maximum centroid-tree level.
size_t distance_to_centroid_id(const size_t node, const size_t centroid) const
Distance from node ID to a centroid ancestor ID.
Node * root() const noexcept
Array< size_t > local_parent_
void append_centroid_annotations(const size_t centroid)
static constexpr size_t NONE
void for_each_centroid_ancestor_id(const size_t node, F &&f) const
Visit each centroid ancestor of node ID.
size_t id_of(const Node *node) const
Array< size_t > collect_component_nodes(const size_t start)
void for_each_centroid_ancestor(const Node *node, F &&f) const
Visit each centroid ancestor of node.
const Array< size_t > & centroid_distances_of_id(const size_t id) const
Distances to centroid ancestors (aligned with centroid_ancestors_of_id).
Gen_Centroid_Decomposition(const GT &g, SA sa=SA())
Construct using the first graph node as root.
size_t size() const noexcept
size_t choose_centroid(const Array< size_t > &nodes)
Array< Array< size_t > > centroid_ancestors_
size_t root_id() const noexcept
Segment-tree-powered path/subtree queries over an HLD layout.
Gen_Heavy_Light_Decomposition< GT, SA > hld_
T query_subtree(const Node *node) const
Subtree query for node in O(log n).
static Array< T > build_base_from_node_info(const Gen_Heavy_Light_Decomposition< GT, SA > &hld)
void set_node(const Node *node, const T &value)
Point assignment: a[node] = value.
T query_path(const Node *u, const Node *v) const
Path query between two nodes in O(log^2 n).
void update_node(const Node *node, const T &delta)
Point update: a[node] = Op(a[node], delta).
Gen_HLD_Path_Query(const GT &g, Node *root, const T &identity, Op op=Op(), SA sa=SA())
Construct from graph/root using node->get_info() as initial values.
void ensure_not_empty(const char *where) const
const Gen_Heavy_Light_Decomposition< GT, SA > & decomposition() const noexcept
T query_path_id(const size_t u, const size_t v) const
Path query between two node IDs in O(log^2 n).
Gen_HLD_Path_Query(const GT &g, const T &identity, Op op=Op(), SA sa=SA())
Construct from graph (first node as root) using node->get_info().
T get_node_id(const size_t id) const
Return current value at node ID.
size_t size() const noexcept
T query_subtree_id(const size_t id) const
Subtree query for node ID in O(log n).
void update_node_id(const size_t id, const T &delta)
Point update: a[id] = Op(a[id], delta).
bool is_empty() const noexcept
void set_node_id(const size_t id, const T &value)
Point assignment: a[id] = value.
Gen_Segment_Tree< T, Op > segment_tree_
and static std::convertible_to< std::invoke_result_t< Getter, Node * >, T > Array< T > build_base_array(const Gen_Heavy_Light_Decomposition< GT, SA > &hld, Getter getter)
and std::convertible_to< std::invoke_result_t< Getter, Node * >, T > Gen_HLD_Path_Query(const GT &g, Node *root, Getter getter, const T &identity, Op op=Op(), SA sa=SA())
Construct with custom node-to-value getter.
and std::convertible_to< std::invoke_result_t< Getter, Node * >, T > Gen_HLD_Path_Query(const GT &g, Getter getter, const T &identity, Op op=Op(), SA sa=SA())
Construct with custom getter and implicit root (first node).
T get_node(const Node *node) const
Return current value at node.
Heavy-Light Decomposition over a rooted tree represented as an Aleph graph.
Gen_Heavy_Light_Decomposition(const GT &g, SA sa=SA())
Construct using the first graph node as root.
size_t position_of(const Node *node) const
static constexpr size_t NONE
void for_each_path_segment_id(size_t u, size_t v, F &&visit) const
Enumerate path segments from u to v in path order.
Array< size_t > subtree_size_
size_t parent_id(const size_t id) const
size_t root_id() const noexcept
size_t head_id(const size_t id) const
size_t distance_id(const size_t u, const size_t v) const
Distance (number of edges) between two node IDs.
size_t lca_id(size_t u, size_t v) const
Lowest common ancestor in O(log n).
size_t position_of_id(const size_t id) const
Node * head_of(const Node *node) const
size_t distance(const Node *u, const Node *v) const
Distance (number of edges) between two nodes.
size_t subtree_size_of_id(const size_t id) const
size_t depth_of_id(const size_t id) const
size_t heavy_child_id(const size_t id) const
void ensure_not_empty(const char *where) const
Node * lca(const Node *u, const Node *v) const
Lowest common ancestor in O(log n).
Node * heavy_child(const Node *node) const
bool is_ancestor(const Node *u, const Node *v) const
True iff u is ancestor of v in the rooted tree.
Range subtree_range(const Node *node) const
Base-array range of a full subtree (inclusive endpoints).
size_t id_of(const Node *node) const
size_t depth_of(const Node *node) const
Gen_Heavy_Light_Decomposition(const GT &g, Node *root, SA sa=SA())
Construct using an explicit root node.
Node * node_of(const size_t id) const
size_t subtree_size_of(const Node *node) const
Range subtree_range_id(const size_t id) const
Base-array range of a full subtree (inclusive endpoints).
Node * parent_of(const Node *node) const
Node * root() const noexcept
bool is_ancestor_id(const size_t u, const size_t v) const
True iff u is ancestor of v in the rooted tree.
void for_each_path_segment(const Node *u, const Node *v, F &&visit) const
Enumerate path segments from u to v in path order.
void for_each_path_segment_undirected_id(const size_t u, const size_t v, F &&visit) const
Enumerate path segments ignoring direction.
void build_decomposition()
size_t size() const noexcept
bool is_empty() const noexcept
Segment tree over an arbitrary associative binary operation.
typename Node::Node_Type Node_Type
The arc class type.
Graph_Node< Node_Info > Node
The graph type.
Graph_Arc< Arc_Info > Arc
The node class type.
Filtered iterator on the nodes of a graph.
Node * node_of(const size_t id) const
bool is_empty() const noexcept
void validate_id(const size_t id, const char *where) const
MapOLhash< Node *, size_t > node_to_id_
std::pair< size_t, size_t > Pair_Key
const Array< Node * > & id_to_node() const noexcept
void build_simple_adjacency()
void validate_connected_acyclic() const
size_t root_id() const noexcept
Rooted_Tree_Topology(const GT &g, Node *root, SA sa=SA())
static constexpr size_t NONE
size_t size() const noexcept
size_t id_of(const Node *node) const
Node * root() const noexcept
Array< Array< size_t > > adjacency_
const Array< Array< size_t > > & adjacency() const noexcept
Array< Node * > id_to_node_
void check_id(const size_t id, const char *where) const
static Pair_Key normalize_pair(size_t u, size_t v) noexcept
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
__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)
DynArray< Graph::Node * > nodes
Main namespace for Aleph-w library functions.
and
Check uniqueness with explicit hash + equality functors.
size_t size(Node *root) noexcept
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
Container< T > range(const T start, const T end, const T step=1)
Generate a range of values [start, end] with a given step.
Filtered iterator on all the arcs of a graph.
Default filter for filtered iterators on arcs.
Open addressing hash map using linear probing.
Data & find(const Key &key)
Find and return the value for a key.
Pair * insert(const Key &key, const Data &data)
Insert a key-value pair (copy semantics).
Pair * search(const Key &key) const noexcept
Search for a key in the map.
Task with priority for job scheduling.
Dynamic array container with automatic resizing.
Dynamic stack implementation based on linked lists.
Dynamic map with open hashing.
Dynamic key-value map based on balanced binary search trees.
Generic graph and digraph implementations.
Segment trees for dynamic range queries with lazy propagation.