Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
LCA.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
93#ifndef LCA_H
94#define LCA_H
95
96#include <algorithm>
97#include <bit>
98#include <cstddef>
99#include <limits>
100#include <utility>
101
102#include <ah-errors.H>
103#include <tpl_array.H>
104#include <tpl_dynListStack.H>
105#include <tpl_dynMapOhash.H>
106#include <tpl_dynMapTree.H>
107#include <tpl_graph.H>
108#include <tpl_sparse_table.H>
109
110namespace Aleph
111{
112 namespace lca_detail
113 {
125 template <class GT, class SA>
127 {
128 public:
129 using Node = typename GT::Node;
130 using Arc = typename GT::Arc;
131
132 static constexpr size_t NONE = std::numeric_limits<size_t>::max();
133
134 private:
135 using Pair_Key = std::pair<size_t, size_t>;
136
137 const GT * graph_ = nullptr;
139 Node * root_ = nullptr;
140 size_t root_id_ = NONE;
141
142 size_t n_ = 0;
143
146
154 size_t euler_size_ = 0;
155
156 static Pair_Key normalize_pair(size_t u, size_t v) noexcept
157 {
158 if (u > v)
159 std::swap(u, v);
160 return std::make_pair(u, v);
161 }
162
164 {
166
167 if (n_ == 0)
168 {
169 ah_domain_error_if(root_ != nullptr)
170 << "Rooted_Tree_Data: root node provided but graph is empty";
171 return;
172 }
173
175 {
177 node_to_id_.swap(tmp);
178 }
179
180 size_t next_id = 0;
181 for (Node_Iterator<GT> it(*graph_); it.has_curr(); it.next_ne())
182 {
183 Node * p = it.get_curr();
184 id_to_node_(next_id) = p;
186 ++next_id;
187 }
188
190 << "Rooted_Tree_Data: failed to index all graph nodes";
191
192 if (root_ == nullptr)
193 root_ = id_to_node_(0);
194
196 << "Rooted_Tree_Data: root node does not belong to graph";
197
199 }
200
202 {
203 if (n_ == 0)
204 return;
205
206 adjacency_.empty();
207 adjacency_.reserve(n_);
208 for (size_t i = 0; i < n_; ++i)
209 adjacency_.append(Array<size_t>());
210
212 size_t edge_count = 0;
213
214 for (Arc_Iterator<GT, SA> it(*graph_, sa_); it.has_curr(); it.next_ne())
215 {
216 Arc * a = it.get_curr_ne();
217 Node * src = graph_->get_src_node(a);
218 Node * tgt = graph_->get_tgt_node(a);
219
220 const auto * src_item = node_to_id_.search(src);
221 const auto * tgt_item = node_to_id_.search(tgt);
222
223 ah_runtime_error_unless(src_item != nullptr and tgt_item != nullptr)
224 << "Rooted_Tree_Data: arc endpoint is not indexed";
225
226 const size_t u = src_item->second;
227 const size_t v = tgt_item->second;
228
229 ah_domain_error_if(u == v)
230 << "Rooted_Tree_Data: self-loop detected in filtered graph";
231
232 const Pair_Key key = normalize_pair(u, v);
233 ah_domain_error_if(unique_edges.search(key) != nullptr)
234 << "Rooted_Tree_Data: parallel/duplicate edge detected in filtered graph";
235
236 unique_edges.insert(key, 1);
237 ++edge_count;
238 }
239
241 << "Rooted_Tree_Data: filtered graph is not a tree (expected "
242 << (n_ - 1) << " edges, got " << edge_count << ")";
243
245 it.has_curr(); it.next_ne())
246 {
247 const auto & [fst, snd] = it.get_curr();
248 const size_t u = fst.first;
249 const size_t v = fst.second;
250 adjacency_(u).append(v);
251 adjacency_(v).append(u);
252 }
253 }
254
256 {
257 if (n_ == 0)
258 return;
259
266
267 for (size_t i = 0; i < n_; ++i)
268 parent_(i) = NONE;
269
271 for (size_t i = 0; i < n_; ++i)
272 visited(i) = 0;
273
274 struct Frame
275 {
276 size_t node;
277 size_t parent;
278 size_t next_child;
279 };
280
282
283 size_t timer = 0;
284 size_t visited_count = 1;
285
286 visited(root_id_) = 1;
287 depth_(root_id_) = 0;
289 tin_(root_id_) = timer++;
290
291 euler_size_ = 0;
294
295 stack.push({root_id_, NONE, 0});
296
297 while (not stack.is_empty())
298 {
299 auto & fr = stack.top();
300
301 if (fr.next_child == adjacency_(fr.node).size())
302 {
303 tout_(fr.node) = timer - 1;
304 (void) stack.pop();
305 if (not stack.is_empty())
306 euler_(euler_size_++) = stack.top().node;
307 continue;
308 }
309
310 const size_t nxt = adjacency_(fr.node)(fr.next_child++);
311 if (nxt == fr.parent)
312 continue;
313
314 ah_domain_error_if(visited(nxt))
315 << "Rooted_Tree_Data: filtered graph is not acyclic";
316
317 visited(nxt) = 1;
319
320 parent_(nxt) = fr.node;
321 depth_(nxt) = depth_(fr.node) + 1;
322 tin_(nxt) = timer++;
323
326
327 stack.push({nxt, fr.node, 0});
328 }
329
331 << "Rooted_Tree_Data: filtered graph is not connected";
332
334 << "Rooted_Tree_Data: unexpected Euler tour size";
335 }
336
337 void check_id(const size_t id, const char * where) const
338 {
340 << where << ": id=" << id << " is out of range [0, " << n_ << ")";
341 }
342
343 public:
344 Rooted_Tree_Data(const GT & g, Node * root, SA sa = SA())
345 : graph_(&g), sa_(std::move(sa)), root_(root)
346 {
347 index_nodes();
350 }
351
352 [[nodiscard]] size_t size() const noexcept { return n_; }
353 [[nodiscard]] bool is_empty() const noexcept { return n_ == 0; }
354 [[nodiscard]] Node * root() const noexcept { return root_; }
355 [[nodiscard]] size_t root_id() const noexcept { return root_id_; }
356
360 [[nodiscard]] const Array<size_t> &tin() const noexcept { return tin_; }
365
366 [[nodiscard]] size_t id_of(const Node * node) const
367 {
368 ah_invalid_argument_if(node == nullptr)
369 << "Rooted_Tree_Data::id_of: null node";
370
371 const auto * item = node_to_id_.search(const_cast<Node *>(node));
372 ah_domain_error_if(item == nullptr)
373 << "Rooted_Tree_Data::id_of: node does not belong to graph";
374
375 return item->second;
376 }
377
378 [[nodiscard]] Node * node_of(const size_t id) const
379 {
380 check_id(id, "Rooted_Tree_Data::node_of");
381 return id_to_node_(id);
382 }
383
384 void validate_id(const size_t id, const char * where) const
385 {
386 check_id(id, where);
387 }
388
389 [[nodiscard]] bool is_ancestor(const size_t u, const size_t v) const
390 {
391 check_id(u, "Rooted_Tree_Data::is_ancestor");
392 check_id(v, "Rooted_Tree_Data::is_ancestor");
393 return tin_(u) <= tin_(v) and tout_(v) <= tout_(u);
394 }
395 };
396
397
399 {
400 size_t depth = 0;
401 size_t node = 0;
402 };
403
405 {
406 Depth_Node operator()(const Depth_Node & a, const Depth_Node & b) const noexcept
407 {
408 if (a.depth < b.depth)
409 return a;
410 if (b.depth < a.depth)
411 return b;
412 return (a.node <= b.node) ? a : b;
413 }
414 };
415 } // namespace lca_detail
416
417
438 template <class GT, class SA = Dft_Show_Arc<GT>>
440 {
441 public:
442 using Node = typename GT::Node;
443
444 private:
446 static constexpr size_t NONE = Topology::NONE;
447
449 size_t levels_ = 0;
450 Array<size_t> up_; // flattened: up_[k * n + v]
451
452 [[nodiscard]] size_t n() const noexcept { return topology_.size(); }
453
454 size_t & up_at(const size_t k, const size_t v) noexcept
455 {
456 return up_(k * n() + v);
457 }
458
459 [[nodiscard]] size_t up_at(const size_t k, const size_t v) const noexcept
460 {
461 return up_(k * n() + v);
462 }
463
464 void ensure_not_empty(const char * where) const
465 {
466 ah_domain_error_if(is_empty()) << where << ": tree is empty";
467 }
468
471 {
472 if (is_empty())
473 return;
474
475 levels_ = static_cast<size_t>(std::bit_width(n()));
476
478 for (size_t i = 0; i < levels_ * n(); ++i)
479 up_(i) = NONE;
480
481 for (size_t v = 0; v < n(); ++v)
482 up_at(0, v) = topology_.parent()(v);
483
484 for (size_t k = 1; k < levels_; ++k)
485 for (size_t v = 0; v < n(); ++v)
486 {
487 const size_t mid = up_at(k - 1, v);
488 up_at(k, v) = (mid == NONE) ? NONE : up_at(k - 1, mid);
489 }
490 }
491
493 [[nodiscard]] size_t lift(size_t v, size_t delta) const
494 {
495 for (size_t k = 0; k < levels_ and delta > 0 and v != NONE; ++k)
496 if ((delta >> k) & 1U)
497 v = up_at(k, v);
498 return v;
499 }
500
501 public:
511 Gen_Binary_Lifting_LCA(const GT & g, Node * root, SA sa = SA())
512 : topology_(g, root, std::move(sa))
513 {
515 }
516
522 Gen_Binary_Lifting_LCA(const GT & g, SA sa = SA())
523 : topology_(g, nullptr, std::move(sa))
524 {
526 }
527
529 [[nodiscard]] size_t size() const noexcept { return topology_.size(); }
530
533
536
538 [[nodiscard]] size_t root_id() const noexcept { return topology_.root_id(); }
539
541 [[nodiscard]] size_t num_levels() const noexcept { return levels_; }
542
544 [[nodiscard]] Node * node_of(const size_t id) const
545 {
546 return topology_.node_of(id);
547 }
548
550 [[nodiscard]] size_t id_of(const Node * node) const
551 {
552 return topology_.id_of(node);
553 }
554
556 [[nodiscard]] size_t depth_of_id(const size_t id) const
557 {
558 topology_.validate_id(id, "Gen_Binary_Lifting_LCA::depth_of_id");
559 return topology_.depth()(id);
560 }
561
563 [[nodiscard]] size_t depth_of(const Node * node) const
564 {
565 return depth_of_id(id_of(node));
566 }
567
569 [[nodiscard]] size_t parent_id(const size_t id) const
570 {
571 topology_.validate_id(id, "Gen_Binary_Lifting_LCA::parent_id");
572 return topology_.parent()(id);
573 }
574
576 [[nodiscard]] Node * parent_of(const Node * node) const
577 {
578 const size_t pid = parent_id(id_of(node));
579 return pid == NONE ? nullptr : node_of(pid);
580 }
581
583 [[nodiscard]] bool is_ancestor_id(const size_t u, const size_t v) const
584 {
585 return topology_.is_ancestor(u, v);
586 }
587
589 [[nodiscard]] bool is_ancestor(const Node * u, const Node * v) const
590 {
591 return is_ancestor_id(id_of(u), id_of(v));
592 }
593
600 [[nodiscard]] size_t kth_ancestor_id(const size_t id, const size_t k) const
601 {
602 topology_.validate_id(id, "Gen_Binary_Lifting_LCA::kth_ancestor_id");
603 if (k > topology_.depth()(id))
604 return NONE;
605 return lift(id, k);
606 }
607
612 [[nodiscard]] Node * kth_ancestor(const Node * node, const size_t k) const
613 {
614 const size_t a = kth_ancestor_id(id_of(node), k);
615 return a == NONE ? nullptr : node_of(a);
616 }
617
619 [[nodiscard]] size_t lca_id(size_t u, size_t v) const
620 {
621 ensure_not_empty("Gen_Binary_Lifting_LCA::lca_id");
622 topology_.validate_id(u, "Gen_Binary_Lifting_LCA::lca_id");
623 topology_.validate_id(v, "Gen_Binary_Lifting_LCA::lca_id");
624
625 if (topology_.depth()(u) < topology_.depth()(v))
626 std::swap(u, v);
627
628 u = lift(u, topology_.depth()(u) - topology_.depth()(v));
629 if (u == v)
630 return u;
631
632 for (size_t k = levels_; k-- > 0;)
633 {
634 const size_t uu = up_at(k, u);
635 const size_t vv = up_at(k, v);
636 if (uu != vv)
637 {
638 u = uu;
639 v = vv;
640 }
641 }
642
643 const size_t ret = topology_.parent()(u);
645 << "Gen_Binary_Lifting_LCA::lca_id: internal invalid parent";
646 return ret;
647 }
648
650 [[nodiscard]] Node * lca(const Node * u, const Node * v) const
651 {
652 return node_of(lca_id(id_of(u), id_of(v)));
653 }
654
656 [[nodiscard]] size_t distance_id(const size_t u, const size_t v) const
657 {
658 const size_t a = lca_id(u, v);
659 return topology_.depth()(u) + topology_.depth()(v) - 2 * topology_.depth()(a);
660 }
661
663 [[nodiscard]] size_t distance(const Node * u, const Node * v) const
664 {
665 return distance_id(id_of(u), id_of(v));
666 }
667 };
668
669
690 template <class GT, class SA = Dft_Show_Arc<GT>>
692 {
693 public:
694 using Node = typename GT::Node;
695
696 private:
698 static constexpr size_t NONE = Topology::NONE;
701
705
706 void ensure_not_empty(const char * where) const
707 {
708 ah_domain_error_if(is_empty()) << where << ": tree is empty";
709 }
710
713 {
714 if (is_empty())
715 return;
716
718 for (size_t i = 0; i < topology_.euler_size(); ++i)
719 {
720 const size_t node = topology_.euler()(i);
721 euler_depth_(i) = Depth_Node{topology_.depth()(node), node};
722 }
723
726 }
727
728 public:
735 Gen_Euler_RMQ_LCA(const GT & g, Node * root, SA sa = SA())
736 : topology_(g, root, std::move(sa)),
738 {
739 build_rmq();
740 }
741
743 Gen_Euler_RMQ_LCA(const GT & g, SA sa = SA())
744 : topology_(g, nullptr, std::move(sa)),
746 {
747 build_rmq();
748 }
749
751 [[nodiscard]] size_t size() const noexcept { return topology_.size(); }
752
755
758
760 [[nodiscard]] size_t root_id() const noexcept { return topology_.root_id(); }
761
763 [[nodiscard]] Node * node_of(const size_t id) const
764 {
765 return topology_.node_of(id);
766 }
767
769 [[nodiscard]] size_t id_of(const Node * node) const
770 {
771 return topology_.id_of(node);
772 }
773
775 [[nodiscard]] size_t depth_of_id(const size_t id) const
776 {
777 topology_.validate_id(id, "Gen_Euler_RMQ_LCA::depth_of_id");
778 return topology_.depth()(id);
779 }
780
782 [[nodiscard]] size_t depth_of(const Node * node) const
783 {
784 return depth_of_id(id_of(node));
785 }
786
788 [[nodiscard]] size_t parent_id(const size_t id) const
789 {
790 topology_.validate_id(id, "Gen_Euler_RMQ_LCA::parent_id");
791 return topology_.parent()(id);
792 }
793
795 [[nodiscard]] Node * parent_of(const Node * node) const
796 {
797 const size_t pid = parent_id(id_of(node));
798 return pid == NONE ? nullptr : node_of(pid);
799 }
800
802 [[nodiscard]] bool is_ancestor_id(const size_t u, const size_t v) const
803 {
804 return topology_.is_ancestor(u, v);
805 }
806
808 [[nodiscard]] bool is_ancestor(const Node * u, const Node * v) const
809 {
810 return is_ancestor_id(id_of(u), id_of(v));
811 }
812
814 [[nodiscard]] size_t lca_id(const size_t u, const size_t v) const
815 {
816 ensure_not_empty("Gen_Euler_RMQ_LCA::lca_id");
817 topology_.validate_id(u, "Gen_Euler_RMQ_LCA::lca_id");
818 topology_.validate_id(v, "Gen_Euler_RMQ_LCA::lca_id");
819
820 size_t l = topology_.first()(u);
821 size_t r = topology_.first()(v);
822 if (l > r)
823 std::swap(l, r);
824
825 return rmq_.query(l, r).node;
826 }
827
829 [[nodiscard]] Node * lca(const Node * u, const Node * v) const
830 {
831 return node_of(lca_id(id_of(u), id_of(v)));
832 }
833
835 [[nodiscard]] size_t distance_id(const size_t u, const size_t v) const
836 {
837 const size_t a = lca_id(u, v);
838 return topology_.depth()(u) + topology_.depth()(v) - 2 * topology_.depth()(a);
839 }
840
842 [[nodiscard]] size_t distance(const Node * u, const Node * v) const
843 {
844 return distance_id(id_of(u), id_of(v));
845 }
846
849 {
850 return topology_.euler();
851 }
852
855 {
856 return topology_.euler_size();
857 }
858 };
859
860
862 template <class GT, class SA = Dft_Show_Arc<GT>>
864
866 template <class GT, class SA = Dft_Show_Arc<GT>>
868} // namespace Aleph
869
870#endif // LCA_H
Exception handling system with formatted messages for Aleph-w.
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
Definition ah-errors.H:250
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:579
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
Definition ah-errors.H:639
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:194
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).
LCA via binary lifting on a rooted tree.
Definition LCA.H:440
size_t depth_of(const Node *node) const
Distance from root to node.
Definition LCA.H:563
size_t depth_of_id(const size_t id) const
Distance from root to node by ID.
Definition LCA.H:556
typename GT::Node Node
Definition LCA.H:442
Gen_Binary_Lifting_LCA(const GT &g, Node *root, SA sa=SA())
Construct from graph + explicit root.
Definition LCA.H:511
bool is_empty() const noexcept
Returns true if the tree has no nodes.
Definition LCA.H:532
Node * node_of(const size_t id) const
Map an internal ID [0, n-1] back to a Node pointer.
Definition LCA.H:544
size_t parent_id(const size_t id) const
Parent ID of node id, or NONE if root.
Definition LCA.H:569
size_t n() const noexcept
Definition LCA.H:452
size_t num_levels() const noexcept
Returns the number of levels in the jump table ( ).
Definition LCA.H:541
size_t distance_id(const size_t u, const size_t v) const
Number of edges on the path between two ids in O(log n).
Definition LCA.H:656
bool is_ancestor(const Node *u, const Node *v) const
Returns true if node u is an ancestor of v (or u == v).
Definition LCA.H:589
Node * kth_ancestor(const Node *node, const size_t k) const
k-th ancestor by node pointer in O(log n).
Definition LCA.H:612
Gen_Binary_Lifting_LCA(const GT &g, SA sa=SA())
Construct using the first graph node as root.
Definition LCA.H:522
size_t kth_ancestor_id(const size_t id, const size_t k) const
k-th ancestor by id in O(log n).
Definition LCA.H:600
size_t & up_at(const size_t k, const size_t v) noexcept
Definition LCA.H:454
size_t up_at(const size_t k, const size_t v) const noexcept
Definition LCA.H:459
Array< size_t > up_
Definition LCA.H:450
size_t id_of(const Node *node) const
Map a Node pointer to its internal ID [0, n-1].
Definition LCA.H:550
Node * root() const noexcept
Returns the root node of the tree.
Definition LCA.H:535
size_t lift(size_t v, size_t delta) const
Definition LCA.H:493
bool is_ancestor_id(const size_t u, const size_t v) const
Returns true if node u is an ancestor of v (or u == v).
Definition LCA.H:583
size_t distance(const Node *u, const Node *v) const
Number of edges on the path between two nodes in O(log n).
Definition LCA.H:663
size_t size() const noexcept
Total number of nodes in the tree.
Definition LCA.H:529
static constexpr size_t NONE
Definition LCA.H:446
size_t root_id() const noexcept
Returns the internal ID of the root node.
Definition LCA.H:538
size_t lca_id(size_t u, size_t v) const
LCA query by node ids in O(log n).
Definition LCA.H:619
Node * parent_of(const Node *node) const
Parent of node, or nullptr if root.
Definition LCA.H:576
Node * lca(const Node *u, const Node *v) const
LCA query by node pointers in O(log n).
Definition LCA.H:650
void ensure_not_empty(const char *where) const
Definition LCA.H:464
LCA via Euler tour + RMQ on depth in a rooted tree.
Definition LCA.H:692
Node * parent_of(const Node *node) const
Parent of node, or nullptr if root.
Definition LCA.H:795
static constexpr size_t NONE
Definition LCA.H:698
Node * node_of(const size_t id) const
Map an internal ID [0, n-1] back to a Node pointer.
Definition LCA.H:763
bool is_empty() const noexcept
Returns true if the tree has no nodes.
Definition LCA.H:754
lca_detail::Depth_Node_Min_Op Depth_Node_Min_Op
Definition LCA.H:700
Gen_Euler_RMQ_LCA(const GT &g, SA sa=SA())
Construct using the first graph node as root.
Definition LCA.H:743
typename GT::Node Node
Definition LCA.H:694
bool is_ancestor(const Node *u, const Node *v) const
Returns true if node u is an ancestor of v (or u == v).
Definition LCA.H:808
size_t id_of(const Node *node) const
Map a Node pointer to its internal ID [0, n-1].
Definition LCA.H:769
size_t depth_of_id(const size_t id) const
Distance from root to node by ID.
Definition LCA.H:775
size_t lca_id(const size_t u, const size_t v) const
LCA query by node ids in O(1).
Definition LCA.H:814
void ensure_not_empty(const char *where) const
Definition LCA.H:706
size_t size() const noexcept
Total number of nodes in the tree.
Definition LCA.H:751
Node * root() const noexcept
Returns the root node of the tree.
Definition LCA.H:757
size_t distance_id(const size_t u, const size_t v) const
Number of edges on the path between two ids in O(1).
Definition LCA.H:835
Gen_Euler_RMQ_LCA(const GT &g, Node *root, SA sa=SA())
Construct from graph + explicit root.
Definition LCA.H:735
size_t root_id() const noexcept
Returns the internal ID of the root node.
Definition LCA.H:760
size_t depth_of(const Node *node) const
Distance from root to node.
Definition LCA.H:782
size_t parent_id(const size_t id) const
Parent ID of node id, or NONE if root.
Definition LCA.H:788
Node * lca(const Node *u, const Node *v) const
LCA query by node pointers in O(1).
Definition LCA.H:829
bool is_ancestor_id(const size_t u, const size_t v) const
Returns true if node u is an ancestor of v (or u == v).
Definition LCA.H:802
size_t euler_tour_size() const noexcept
Euler tour size ( for empty tree, else ).
Definition LCA.H:854
const Array< size_t > & euler_tour() const noexcept
Euler tour sequence of node ids ( entries).
Definition LCA.H:848
size_t distance(const Node *u, const Node *v) const
Number of edges on the path between two nodes in O(1).
Definition LCA.H:842
Gen_Sparse_Table< Depth_Node, Depth_Node_Min_Op > rmq_
Definition LCA.H:704
Array< Depth_Node > euler_depth_
Definition LCA.H:703
Sparse Table over an arbitrary associative and idempotent binary operation.
Filtered iterator on the nodes of a graph.
Definition tpl_graph.H:1206
Rooted_Tree_Data(const GT &g, Node *root, SA sa=SA())
Definition LCA.H:344
size_t root_id() const noexcept
Definition LCA.H:355
const Array< size_t > & depth() const noexcept
Definition LCA.H:359
Array< Array< size_t > > adjacency_
Definition LCA.H:147
MapOLhash< Node *, size_t > node_to_id_
Definition LCA.H:145
size_t size() const noexcept
Definition LCA.H:352
const Array< Node * > & id_to_node() const noexcept
Definition LCA.H:357
size_t euler_size() const noexcept
Definition LCA.H:364
Array< Node * > id_to_node_
Definition LCA.H:144
const Array< size_t > & euler() const noexcept
Definition LCA.H:363
static constexpr size_t NONE
Definition LCA.H:132
static Pair_Key normalize_pair(size_t u, size_t v) noexcept
Definition LCA.H:156
void check_id(const size_t id, const char *where) const
Definition LCA.H:337
Node * root() const noexcept
Definition LCA.H:354
bool is_ancestor(const size_t u, const size_t v) const
Definition LCA.H:389
const Array< size_t > & first() const noexcept
Definition LCA.H:362
const Array< size_t > & tout() const noexcept
Definition LCA.H:361
const Array< size_t > & tin() const noexcept
Definition LCA.H:360
Node * node_of(const size_t id) const
Definition LCA.H:378
const Array< size_t > & parent() const noexcept
Definition LCA.H:358
void validate_id(const size_t id, const char *where) const
Definition LCA.H:384
size_t id_of(const Node *node) const
Definition LCA.H:366
std::pair< size_t, size_t > Pair_Key
Definition LCA.H:135
bool is_empty() const noexcept
Definition LCA.H:353
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:737
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:695
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:743
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
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.
STL namespace.
Filtered iterator on all the arcs of a graph.
Definition tpl_graph.H:1164
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.
Depth_Node operator()(const Depth_Node &a, const Depth_Node &b) const noexcept
Definition LCA.H:406
static int * k
gsl_rng * r
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.
Sparse Table for static range queries in O(1).
DynList< int > l