Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_mo_on_trees.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
89# ifndef TPL_MO_ON_TREES_H
90# define TPL_MO_ON_TREES_H
91
92# include <ah-graph-concepts.H>
93
94# include <algorithm>
95# include <cmath>
96# include <concepts>
97# include <vector>
98# include <tpl_array.H>
99# include <tpl_dynMapOhash.H>
100# include <tpl_dynList.H>
101# include <tpl_dynListStack.H>
102# include <tpl_mo_algorithm.H>
103# include <tpl_tree_node.H>
104# include <ah-errors.H>
105
106namespace Aleph
107{
117 template <class GT>
118 concept MoTreeGraph = requires(const GT & g,
119 typename GT::Node * p,
120 typename GT::Arc * a)
121 {
122 typename GT::Node;
123 typename GT::Arc;
124 typename GT::Node::Node_Type;
125 typename GT::Node_Arc_Iterator;
126 { g.vsize() } -> std::convertible_to<size_t>;
127 { g.get_connected_node(a, p) } -> std::same_as<typename GT::Node *>;
128 { typename GT::Node_Arc_Iterator(p) };
129 { g.for_each_node([](typename GT::Node *) {}) };
130 };
131
132 // ================================================================
133 // Gen_Mo_On_Trees
134 // ================================================================
135
167 template <AlephGraph GT, class Policy>
170 {
171 public:
172 using Node = typename GT::Node;
173 using Arc = typename GT::Arc;
174 using T = typename Node::Node_Type;
175 using answer_type = typename Policy::answer_type;
176
177 private:
178 static constexpr size_t NONE = ~static_cast<size_t>(0);
179
180 const GT & g_;
182 mutable Policy pol_;
183 size_t n_ = 0;
184
185 // Node <-> ID mapping (external, zero impact on graph)
189
190 // Single-occurrence Euler tour (for subtree queries, size n)
194
195 // Double-occurrence Euler tour (for path queries, size 2n)
199
200 // Binary lifting for LCA
201 size_t log_n_ = 0;
204 Array<size_t> up_; // flattened [log_n_][n_]: up_(k * n_ + v)
205
206 // ── Build helpers ──────────────────────────────────────────────
207
208 void build()
209 {
210 n_ = g_.vsize();
211 if (n_ == 0)
212 return;
213
214 // 1. Assign contiguous IDs to nodes (pre-allocate OLhash for n_ entries)
217 {
219 node_to_id_.swap(tmp);
220 }
221
222 {
223 size_t next_id = 0;
224 g_.for_each_node([&](Node * p)
225 {
227 id_to_node_(next_id) = p;
228 node_values_(next_id) = p->get_info();
229 ++next_id;
230 });
231 }
232
234 << "Gen_Mo_On_Trees: root node not found in graph";
235
236 // 2. Pre-collect adjacency lists as node IDs (Array for O(1) access)
237 auto adj = Array<Array<size_t>>::create(n_);
238 g_.for_each_node([&](Node * p)
239 {
240 const size_t pid = node_to_id_.find(p);
242 for (auto it = typename GT::Node_Arc_Iterator(p);
243 it.has_curr(); it.next_ne())
244 {
245 auto * a = it.get_curr();
246 auto * neighbor = g_.get_connected_node(a, p);
247 neighbors.append(node_to_id_.find(neighbor));
248 }
249 adj(pid) = Array<size_t>(neighbors);
250 });
251
252 // 3. Iterative DFS to build Euler tours + parent/depth
261 for (size_t i = 0; i < n_; ++i)
262 parent_(i) = NONE;
263
264 auto visited = Array<bool>::create(n_);
265 for (size_t i = 0; i < n_; ++i)
266 visited(i) = false;
267
268 size_t sub_timer = 0;
269 size_t path_timer = 0;
270
271 struct Frame { size_t id; size_t child_idx; };
273
274 const size_t root_id = node_to_id_.find(root_);
275 visited(root_id) = true;
276 depth_(root_id) = 0;
277 parent_(root_id) = NONE;
278
279 tin_(root_id) = sub_timer;
280 flat_sub_(sub_timer) = node_values_(root_id);
281 ++sub_timer;
282
283 first_(root_id) = path_timer;
284 flat_node_(path_timer) = root_id;
285 ++path_timer;
286
287 stk.push({root_id, 0});
288
289 while (not stk.is_empty())
290 {
291 auto & fr = stk.top();
292 bool pushed = false;
293
294 while (fr.child_idx < adj(fr.id).size())
295 {
296 const size_t nid = adj(fr.id)(fr.child_idx++);
297 if (visited(nid))
298 continue;
299
300 visited(nid) = true;
301 parent_(nid) = fr.id;
302 depth_(nid) = depth_(fr.id) + 1;
303
304 tin_(nid) = sub_timer;
306 ++sub_timer;
307
310 ++path_timer;
311
312 stk.push({nid, 0});
313 pushed = true;
314 break;
315 }
316
317 if (not pushed)
318 {
319 tout_(fr.id) = sub_timer - 1;
320
321 last_(fr.id) = path_timer;
323 ++path_timer;
324
325 (void) stk.pop();
326 }
327 }
328
330 << "Gen_Mo_On_Trees: graph is not connected (not a tree)";
331
332 // 4. Binary lifting table for LCA
333 log_n_ = 1;
334 while ((static_cast<size_t>(1) << log_n_) < n_)
335 ++log_n_;
336 ++log_n_;
337
339 for (size_t i = 0; i < log_n_ * n_; ++i)
340 up_(i) = NONE;
341
342 for (size_t v = 0; v < n_; ++v)
343 up_(0 * n_ + v) = parent_(v);
344
345 for (size_t k = 1; k < log_n_; ++k)
346 for (size_t v = 0; v < n_; ++v)
347 up_(k * n_ + v) = (up_((k-1) * n_ + v) == NONE)
348 ? NONE
349 : up_((k-1) * n_ + up_((k-1) * n_ + v));
350 }
351
352 // LCA via binary lifting – O(log N)
353 size_t lca(size_t u, size_t v) const
354 {
355 if (depth_(u) < depth_(v))
356 std::swap(u, v);
357
358 const size_t diff = depth_(u) - depth_(v);
359 for (size_t k = 0; k < log_n_; ++k)
360 if ((diff >> k) & 1)
361 u = up_(k * n_ + u);
362
363 if (u == v)
364 return u;
365
366 for (int k = static_cast<int>(log_n_) - 1; k >= 0; --k)
367 if (up_(k * n_ + u) != up_(k * n_ + v))
368 {
369 u = up_(k * n_ + u);
370 v = up_(k * n_ + v);
371 }
372
373 return up_(0 * n_ + u);
374 }
375
376 // Standard Mo sweep (used for subtree queries)
379 size_t n) const
380 {
381 const size_t q = queries.size();
382 const size_t block = std::max<size_t>(
383 1, static_cast<size_t>(std::sqrt(static_cast<double>(n))));
384
385 std::sort(&queries(0), &queries(0) + q,
386 [block](const Mo_Query & a, const Mo_Query & b)
387 {
388 const size_t ba = a.l / block;
389 const size_t bb = b.l / block;
390 if (ba != bb)
391 return ba < bb;
392 return (ba & 1) ? (a.r > b.r) : (a.r < b.r);
393 });
394
395 pol_.init(data, n);
396
398
399 size_t cur_l = queries(0).l;
400 size_t cur_r = queries(0).l;
401 pol_.add(data, cur_l);
402
403 while (cur_r < queries(0).r)
404 pol_.add(data, ++cur_r);
405
406 answers(queries(0).id) = pol_.answer();
407
408 for (size_t i = 1; i < q; ++i)
409 {
410 const size_t ql = queries(i).l;
411 const size_t qr = queries(i).r;
412
413 while (cur_r < qr)
414 pol_.add(data, ++cur_r);
415
416 while (cur_l > ql)
417 pol_.add(data, --cur_l);
418
419 while (cur_r > qr)
420 pol_.remove(data, cur_r--);
421
422 while (cur_l < ql)
423 pol_.remove(data, cur_l++);
424
425 answers(queries(i).id) = pol_.answer();
426 }
427
428 return answers;
429 }
430
431 public:
432
450 : g_(g), root_(root), pol_(std::move(p))
451 {
452 build();
453 }
454
456 [[nodiscard]] size_t size() const noexcept { return n_; }
457
459 [[nodiscard]] bool is_empty() const noexcept { return n_ == 0; }
460
461 // ── Subtree queries ──────────────────────────────────────────
462
482 const Array<Node*> & query_roots) const
483 {
484 const size_t q = query_roots.size();
485 if (q == 0)
486 return Array<answer_type>();
487
489 for (size_t i = 0; i < q; ++i)
490 {
491 auto * p = node_to_id_.search(query_roots(i));
492 ah_domain_error_if(p == nullptr)
493 << "subtree_solve: query " << i << " node not in tree";
494 const size_t id = p->second;
495 queries(i) = {tin_(id), tout_(id), i};
496 }
497
498 return mo_sweep(flat_sub_, std::move(queries), n_);
499 }
500
513 std::initializer_list<Node*> il) const
514 {
515 const Array<Node*> roots(il);
516 return subtree_solve(roots);
517 }
518
519 // ── Path queries ─────────────────────────────────────────────
520
542 const Array<std::pair<Node*, Node*>> & query_pairs) const
543 {
544 const size_t q = query_pairs.size();
545 if (q == 0)
546 return Array<answer_type>();
547
548 struct Path_Query
549 {
550 size_t l, r, id, lca_id;
551 };
552
554 for (size_t i = 0; i < q; ++i)
555 {
556 auto * pu = node_to_id_.search(query_pairs(i).first);
557 auto * pv = node_to_id_.search(query_pairs(i).second);
558 ah_domain_error_if(pu == nullptr or pv == nullptr)
559 << "path_solve: query " << i << " node not in tree";
560
561 size_t u = pu->second;
562 size_t v = pv->second;
563
564 if (first_(u) > first_(v))
565 std::swap(u, v);
566
567 if (const size_t ancestor = lca(u, v); ancestor == u)
568 pqueries(i) = {first_(u), first_(v), i, NONE};
569 else
570 pqueries(i) = {last_(u), first_(v), i, ancestor};
571 }
572
573 // Snake sort
574 const size_t tour_sz = 2 * n_;
575 const size_t block = std::max<size_t>(
576 1, static_cast<size_t>(
577 std::sqrt(static_cast<double>(tour_sz))));
578
579 std::sort(&pqueries(0), &pqueries(0) + q,
580 [block](const Path_Query & a, const Path_Query & b)
581 {
582 const size_t ba = a.l / block;
583 const size_t bb = b.l / block;
584 if (ba != bb)
585 return ba < bb;
586 return (ba & 1) ? (a.r > b.r) : (a.r < b.r);
587 });
588
589 pol_.init(node_values_, n_);
590
592 auto active = Array<bool>::create(n_);
593 for (size_t i = 0; i < n_; ++i)
594 active(i) = false;
595
596 // Toggle: flip node activity and call policy add/remove
597 auto toggle = [&](const size_t pos)
598 {
599 if (const size_t nid = flat_node_(pos); active(nid))
600 {
601 pol_.remove(node_values_, nid);
602 active(nid) = false;
603 }
604 else
605 {
606 pol_.add(node_values_, nid);
607 active(nid) = true;
608 }
609 };
610
611 // Initialize window to first query
612 size_t cur_l = pqueries(0).l;
613 size_t cur_r = pqueries(0).l;
614 toggle(cur_l);
615
616 while (cur_r < pqueries(0).r)
617 toggle(++cur_r);
618
619 if (pqueries(0).lca_id != NONE)
620 {
621 pol_.add(node_values_, pqueries(0).lca_id);
622 answers(pqueries(0).id) = pol_.answer();
623 pol_.remove(node_values_, pqueries(0).lca_id);
624 }
625 else
626 answers(pqueries(0).id) = pol_.answer();
627
628 // Sweep remaining queries
629 for (size_t i = 1; i < q; ++i)
630 {
631 const size_t ql = pqueries(i).l;
632 const size_t qr = pqueries(i).r;
633
634 while (cur_r < qr) toggle(++cur_r);
635 while (cur_l > ql) toggle(--cur_l);
636 while (cur_r > qr) toggle(cur_r--);
637 while (cur_l < ql) toggle(cur_l++);
638
639 if (pqueries(i).lca_id != NONE)
640 {
641 pol_.add(node_values_, pqueries(i).lca_id);
642 answers(pqueries(i).id) = pol_.answer();
643 pol_.remove(node_values_, pqueries(i).lca_id);
644 }
645 else
646 answers(pqueries(i).id) = pol_.answer();
647 }
648
649 return answers;
650 }
651
665 std::initializer_list<std::pair<Node*, Node*>> il) const
666 {
667 const Array<std::pair<Node*, Node*>> pairs(il);
668 return path_solve(pairs);
669 }
670 };
671
672 // ================================================================
673 // Gen_Mo_On_Tree_Node — Mo on N-ary trees (Tree_Node<T>)
674 // ================================================================
675
700 template <typename T, class Policy>
701 requires MoPolicy<Policy, T>
703 {
704 public:
706 using answer_type = typename Policy::answer_type;
707
708 private:
709 static constexpr size_t NONE = ~size_t(0);
710
712 mutable Policy pol_;
713 size_t n_ = 0;
714
715 // Node <-> ID mapping
719
720 // Single-occurrence Euler tour (subtree queries, size n)
724
725 // Double-occurrence Euler tour (path queries, size 2n)
729
730 // Binary lifting for LCA
731 size_t log_n_ = 0;
734 Array<size_t> up_; // flattened [log_n_][n_]: up_(k * n_ + v)
735
736 // ── Build ──────────────────────────────────────────────────────
737
738 void build()
739 {
740 // 1. Collect nodes iteratively in preorder (no recursion).
741 n_ = 0;
742 if (root_ == nullptr)
743 return;
744
746 {
748 stk.push(root_);
749
750 while (not stk.is_empty())
751 {
752 Node * curr = stk.pop();
753 preorder.append(curr);
754 ++n_;
755
756 // Push children right-to-left so stack pops left-to-right.
758 for (Node * c = curr->get_left_child(); c != nullptr;
759 c = c->get_right_sibling())
761
762 while (not rev_children.is_empty())
763 stk.push(rev_children.pop());
764 }
765 }
766
767 if (n_ == 0)
768 return;
769
770 // 2. Assign IDs (pre-allocate OLhash for n_ entries)
773 {
775 node_to_id_.swap(tmp);
776 }
777
778 // Pre-collect adjacency as Array<Array<size_t>> for O(1) indexed access
779 auto adj = Array<Array<size_t>>::create(n_);
780 {
781 size_t next_id = 0;
782 for (auto it = preorder.get_it(); it.has_curr(); it.next_ne())
783 {
784 Node * mp = it.get_curr();
786 id_to_node_(next_id) = mp;
788 ++next_id;
789 }
790
791 // Build adjacency: children plus parent if it belongs to this rooted tree.
792 for (size_t pid = 0; pid < n_; ++pid)
793 {
794 Node * mp = id_to_node_(pid);
796
797 for (Node * c = mp->get_left_child(); c != nullptr;
798 c = c->get_right_sibling())
800
801 Node * par = mp->get_parent();
802 if (par != nullptr)
803 if (auto * pp = node_to_id_.search(par); pp != nullptr)
804 neighbors.append(pp->second);
805
806 adj(pid) = Array<size_t>(neighbors);
807 }
808 }
809
810 // 3. Iterative DFS for Euler tours + parent/depth
819 for (size_t i = 0; i < n_; ++i)
820 parent_(i) = NONE;
821
822 auto visited = Array<bool>::create(n_);
823 for (size_t i = 0; i < n_; ++i)
824 visited(i) = false;
825
826 size_t sub_timer = 0;
827 size_t path_timer = 0;
828
829 struct Frame { size_t id; size_t child_idx; };
831
832 const size_t root_id = node_to_id_.find(root_);
833 visited(root_id) = true;
834 depth_(root_id) = 0;
835 parent_(root_id) = NONE;
836
837 tin_(root_id) = sub_timer;
838 flat_sub_(sub_timer) = node_values_(root_id);
839 ++sub_timer;
840
841 first_(root_id) = path_timer;
842 flat_node_(path_timer) = root_id;
843 ++path_timer;
844
845 stk.push({root_id, 0});
846
847 while (not stk.is_empty())
848 {
849 auto & fr = stk.top();
850 bool pushed = false;
851
852 while (fr.child_idx < adj(fr.id).size())
853 {
854 const size_t nid = adj(fr.id)(fr.child_idx++);
855 if (visited(nid))
856 continue;
857
858 visited(nid) = true;
859 parent_(nid) = fr.id;
860 depth_(nid) = depth_(fr.id) + 1;
861
862 tin_(nid) = sub_timer;
864 ++sub_timer;
865
868 ++path_timer;
869
870 stk.push({nid, 0});
871 pushed = true;
872 break;
873 }
874
875 if (not pushed)
876 {
877 tout_(fr.id) = sub_timer - 1;
878
879 last_(fr.id) = path_timer;
881 ++path_timer;
882
883 (void) stk.pop();
884 }
885 }
886
888 << "Gen_Mo_On_Tree_Node: tree traversal inconsistency";
889
890 // 4. Binary lifting table for LCA
891 log_n_ = 1;
892 while ((static_cast<size_t>(1) << log_n_) < n_)
893 ++log_n_;
894 ++log_n_;
895
897 for (size_t i = 0; i < log_n_ * n_; ++i)
898 up_(i) = NONE;
899
900 for (size_t v = 0; v < n_; ++v)
901 up_(0 * n_ + v) = parent_(v);
902
903 for (size_t k = 1; k < log_n_; ++k)
904 for (size_t v = 0; v < n_; ++v)
905 up_(k * n_ + v) = (up_((k-1) * n_ + v) == NONE)
906 ? NONE
907 : up_((k-1) * n_ + up_((k-1) * n_ + v));
908 }
909
910 // LCA via binary lifting – O(log N)
911 size_t lca(size_t u, size_t v) const
912 {
913 if (depth_(u) < depth_(v))
914 std::swap(u, v);
915
916 size_t diff = depth_(u) - depth_(v);
917 for (size_t k = 0; k < log_n_; ++k)
918 if ((diff >> k) & 1)
919 u = up_(k * n_ + u);
920
921 if (u == v)
922 return u;
923
924 for (int k = static_cast<int>(log_n_) - 1; k >= 0; --k)
925 if (up_(k * n_ + u) != up_(k * n_ + v))
926 {
927 u = up_(k * n_ + u);
928 v = up_(k * n_ + v);
929 }
930
931 return up_(0 * n_ + u);
932 }
933
934 // Standard Mo sweep
937 size_t nn) const
938 {
939 const size_t q = queries.size();
940 const size_t block = std::max<size_t>(
941 1, static_cast<size_t>(std::sqrt(static_cast<double>(nn))));
942
943 std::sort(&queries(0), &queries(0) + q,
944 [block](const Mo_Query & a, const Mo_Query & b)
945 {
946 const size_t ba = a.l / block;
947 const size_t bb = b.l / block;
948 if (ba != bb)
949 return ba < bb;
950 return (ba & 1) ? (a.r > b.r) : (a.r < b.r);
951 });
952
953 pol_.init(data, nn);
954
956
957 size_t cur_l = queries(0).l;
958 size_t cur_r = queries(0).l;
959 pol_.add(data, cur_l);
960
961 while (cur_r < queries(0).r)
962 pol_.add(data, ++cur_r);
963
964 answers(queries(0).id) = pol_.answer();
965
966 for (size_t i = 1; i < q; ++i)
967 {
968 const size_t ql = queries(i).l;
969 const size_t qr = queries(i).r;
970
971 while (cur_r < qr) pol_.add(data, ++cur_r);
972 while (cur_l > ql) pol_.add(data, --cur_l);
973 while (cur_r > qr) pol_.remove(data, cur_r--);
974 while (cur_l < ql) pol_.remove(data, cur_l++);
975
976 answers(queries(i).id) = pol_.answer();
977 }
978
979 return answers;
980 }
981
982 public:
983
998 : root_(root), pol_(std::move(p))
999 {
1000 ah_domain_error_if(root == nullptr)
1001 << "Gen_Mo_On_Tree_Node: root is null";
1002 build();
1003 }
1004
1006 [[nodiscard]] size_t size() const noexcept { return n_; }
1007
1009 [[nodiscard]] bool is_empty() const noexcept { return n_ == 0; }
1010
1011 // ── Subtree queries ──────────────────────────────────────────
1012
1026 const Array<Node*> & query_roots) const
1027 {
1028 const size_t q = query_roots.size();
1029 if (q == 0)
1030 return Array<answer_type>();
1031
1033 for (size_t i = 0; i < q; ++i)
1034 {
1035 auto * p = node_to_id_.search(query_roots(i));
1036 ah_domain_error_if(p == nullptr)
1037 << "subtree_solve: query " << i << " node not in tree";
1038 const size_t id = p->second;
1039 queries(i) = {tin_(id), tout_(id), i};
1040 }
1041
1042 return mo_sweep(flat_sub_, std::move(queries), n_);
1043 }
1044
1057 std::initializer_list<Node*> il) const
1058 {
1059 const Array<Node*> roots(il);
1060 return subtree_solve(roots);
1061 }
1062
1063 // ── Path queries ─────────────────────────────────────────────
1064
1078 const Array<std::pair<Node*, Node*>> & query_pairs) const
1079 {
1080 const size_t q = query_pairs.size();
1081 if (q == 0)
1082 return Array<answer_type>();
1083
1084 struct Path_Query
1085 {
1086 size_t l, r, id, lca_id;
1087 };
1088
1090 for (size_t i = 0; i < q; ++i)
1091 {
1092 auto * pu = node_to_id_.search(query_pairs(i).first);
1093 auto * pv = node_to_id_.search(query_pairs(i).second);
1094 ah_domain_error_if(pu == nullptr or pv == nullptr)
1095 << "path_solve: query " << i << " node not in tree";
1096
1097 size_t u = pu->second;
1098 size_t v = pv->second;
1099
1100 if (first_(u) > first_(v))
1101 std::swap(u, v);
1102
1103 const size_t ancestor = lca(u, v);
1104
1105 if (ancestor == u)
1106 pqueries(i) = {first_(u), first_(v), i, NONE};
1107 else
1108 pqueries(i) = {last_(u), first_(v), i, ancestor};
1109 }
1110
1111 // Snake sort
1112 const size_t tour_sz = 2 * n_;
1113 const size_t block = std::max<size_t>(
1114 1, static_cast<size_t>(
1115 std::sqrt(static_cast<double>(tour_sz))));
1116
1117 std::sort(&pqueries(0), &pqueries(0) + q,
1118 [block](const Path_Query & a, const Path_Query & b)
1119 {
1120 const size_t ba = a.l / block;
1121 const size_t bb = b.l / block;
1122 if (ba != bb)
1123 return ba < bb;
1124 return (ba & 1) ? (a.r > b.r) : (a.r < b.r);
1125 });
1126
1127 pol_.init(node_values_, n_);
1128
1130 auto active = Array<bool>::create(n_);
1131 for (size_t i = 0; i < n_; ++i)
1132 active(i) = false;
1133
1134 auto toggle = [&](const size_t pos)
1135 {
1136 if (const size_t nid = flat_node_(pos); active(nid))
1137 {
1138 pol_.remove(node_values_, nid);
1139 active(nid) = false;
1140 }
1141 else
1142 {
1143 pol_.add(node_values_, nid);
1144 active(nid) = true;
1145 }
1146 };
1147
1148 size_t cur_l = pqueries(0).l;
1149 size_t cur_r = pqueries(0).l;
1150 toggle(cur_l);
1151
1152 while (cur_r < pqueries(0).r)
1153 toggle(++cur_r);
1154
1155 if (pqueries(0).lca_id != NONE)
1156 {
1157 pol_.add(node_values_, pqueries(0).lca_id);
1158 answers(pqueries(0).id) = pol_.answer();
1159 pol_.remove(node_values_, pqueries(0).lca_id);
1160 }
1161 else
1162 answers(pqueries(0).id) = pol_.answer();
1163
1164 for (size_t i = 1; i < q; ++i)
1165 {
1166 const size_t ql = pqueries(i).l;
1167 const size_t qr = pqueries(i).r;
1168
1169 while (cur_r < qr) toggle(++cur_r);
1170 while (cur_l > ql) toggle(--cur_l);
1171 while (cur_r > qr) toggle(cur_r--);
1172 while (cur_l < ql) toggle(cur_l++);
1173
1174 if (pqueries(i).lca_id != NONE)
1175 {
1176 pol_.add(node_values_, pqueries(i).lca_id);
1177 answers(pqueries(i).id) = pol_.answer();
1178 pol_.remove(node_values_, pqueries(i).lca_id);
1179 }
1180 else
1181 answers(pqueries(i).id) = pol_.answer();
1182 }
1183
1184 return answers;
1185 }
1186
1200 std::initializer_list<std::pair<Node*, Node*>> il) const
1201 {
1202 const Array<std::pair<Node*, Node*>> pairs(il);
1203 return path_solve(pairs);
1204 }
1205 };
1206
1207 // ================================================================
1208 // Convenient typedefs
1209 // ================================================================
1210
1215 template <class GT>
1219
1224 template <class GT>
1228
1233 template <class GT>
1237
1242 template <typename T>
1245
1250 template <typename T>
1253
1258 template <typename T>
1261
1262} // namespace Aleph
1263
1264# endif // TPL_MO_ON_TREES_H
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
C++20 concepts for the protocol shared by graph algorithms.
List_Graph< Graph_Node< Node_Info >, Graph_Arc< Arc_Info > > GT
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:196
Iterator get_it()
T & append()
Allocate a new entry to the end of array.
Dynamic stack of elements of generic type T based on a singly linked list.
T & push(const T &data)
Push an item by copy onto the top of the stack.
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
Offline subtree and path queries on N-ary trees (Tree_Node).
static constexpr size_t NONE
Array< answer_type > path_solve(std::initializer_list< std::pair< Node *, Node * > > il) const
Solve path queries (initializer-list overload).
size_t size() const noexcept
Number of nodes in the tree.
size_t lca(size_t u, size_t v) const
MapOLhash< Node *, size_t > node_to_id_
typename Policy::answer_type answer_type
Array< answer_type > mo_sweep(const Array< T > &data, Array< Mo_Query > queries, size_t nn) const
Array< answer_type > path_solve(const Array< std::pair< Node *, Node * > > &query_pairs) const
Answer path queries on the N-ary tree.
Array< answer_type > subtree_solve(std::initializer_list< Node * > il) const
Solve subtree queries (initializer-list overload).
Array< answer_type > subtree_solve(const Array< Node * > &query_roots) const
Answer subtree queries on the N-ary tree.
Gen_Mo_On_Tree_Node(Node *root, Policy p=Policy())
Construct a Mo's algorithm query engine for N-ary trees.
bool is_empty() const noexcept
True if the tree is empty.
Offline subtree and path queries on trees via Mo's algorithm.
typename Policy::answer_type answer_type
typename Node::Node_Type T
Array< answer_type > path_solve(std::initializer_list< std::pair< Node *, Node * > > il) const
Solve path queries (initializer-list overload).
static constexpr size_t NONE
Array< answer_type > subtree_solve(const Array< Node * > &query_roots) const
Answer subtree queries using Mo's algorithm.
Array< Node * > id_to_node_
bool is_empty() const noexcept
True if the tree is empty.
Array< size_t > flat_node_
Array< answer_type > subtree_solve(std::initializer_list< Node * > il) const
Answer subtree queries from an initializer list.
Gen_Mo_On_Trees(const GT &g, Node *root, Policy p=Policy())
Construct a Mo's algorithm query engine for tree queries.
typename GT::Node Node
size_t lca(size_t u, size_t v) const
MapOLhash< Node *, size_t > node_to_id_
size_t size() const noexcept
Number of nodes in the tree.
Array< answer_type > mo_sweep(const Array< T > &data, Array< Mo_Query > queries, size_t n) const
Array< answer_type > path_solve(const Array< std::pair< Node *, Node * > > &query_pairs) const
Answer path queries between node pairs.
typename Node::Node_Type Node_Type
The arc class type.
Definition tpl_graph.H:437
Forward declaration used by CRTP helpers before the full node definition.
Tree_Node * get_left_child() const noexcept
Returns the leftmost child of this.
Tree_Node * get_parent() const noexcept
Returns the parent of this.
T & get_key() noexcept
Returns a modifiable reference to the node contents.
Node * get_connected_node(Arc *arc, Node *node) const noexcept
Return the adjacent node to node through arc.
Definition graph-dry.H:820
void for_each_node(Operation &operation) const
Unconditionally traverse all the nodes of graph and on each one perform an operation.
Definition graph-dry.H:1531
constexpr size_t vsize() const noexcept
Definition graph-dry.H:746
Concept constraining a policy for Mo's algorithm.
Concept constraining a graph type usable for Mo on Trees.
__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)
Definition gmpfrxx.h:4071
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
STL namespace.
Policy: count distinct elements in a range.
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.
A query for Mo's algorithm: inclusive range [l, r] with id.
size_t l
Left endpoint (inclusive, 0-based).
size_t r
Right endpoint (inclusive, 0-based).
Policy: "powerful array" sum = sum(cnt[x]^2 * x).
Policy: range mode (most frequent element).
DynArray< int > preorder
static int * k
gsl_rng * r
Dynamic array container with automatic resizing.
Dynamic stack implementation based on linked lists.
Alias for htlist.H (DynList implementation).
Dynamic map with open hashing.
Mo's algorithm for offline range queries.
General tree (n-ary tree) node.
DynList< int > l