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 <algorithm>
93# include <cmath>
94# include <concepts>
95# include <vector>
96# include <tpl_array.H>
97# include <tpl_dynMapOhash.H>
98# include <tpl_dynList.H>
99# include <tpl_dynListStack.H>
100# include <tpl_mo_algorithm.H>
101# include <tpl_tree_node.H>
102# include <ah-errors.H>
103
104namespace Aleph
105{
115 template <typename GT>
116 concept MoTreeGraph = requires(const GT & g,
117 typename GT::Node * p,
118 typename GT::Arc * a)
119 {
120 typename GT::Node;
121 typename GT::Arc;
122 typename GT::Node::Node_Type;
123 typename GT::Node_Arc_Iterator;
124 { g.vsize() } -> std::convertible_to<size_t>;
125 { g.get_connected_node(a, p) } -> std::same_as<typename GT::Node *>;
126 { typename GT::Node_Arc_Iterator(p) };
127 { g.for_each_node([](typename GT::Node *) {}) };
128 };
129
130 // ================================================================
131 // Gen_Mo_On_Trees
132 // ================================================================
133
165 template <class GT, class Policy>
168 {
169 public:
170 using Node = typename GT::Node;
171 using Arc = typename GT::Arc;
172 using T = typename Node::Node_Type;
173 using answer_type = typename Policy::answer_type;
174
175 private:
176 static constexpr size_t NONE = ~static_cast<size_t>(0);
177
178 const GT & g_;
180 mutable Policy pol_;
181 size_t n_ = 0;
182
183 // Node <-> ID mapping (external, zero impact on graph)
187
188 // Single-occurrence Euler tour (for subtree queries, size n)
192
193 // Double-occurrence Euler tour (for path queries, size 2n)
197
198 // Binary lifting for LCA
199 size_t log_n_ = 0;
202 Array<size_t> up_; // flattened [log_n_][n_]: up_(k * n_ + v)
203
204 // ── Build helpers ──────────────────────────────────────────────
205
206 void build()
207 {
208 n_ = g_.vsize();
209 if (n_ == 0)
210 return;
211
212 // 1. Assign contiguous IDs to nodes (pre-allocate OLhash for n_ entries)
215 {
217 node_to_id_.swap(tmp);
218 }
219
220 {
221 size_t next_id = 0;
222 g_.for_each_node([&](Node * p)
223 {
225 id_to_node_(next_id) = p;
226 node_values_(next_id) = p->get_info();
227 ++next_id;
228 });
229 }
230
232 << "Gen_Mo_On_Trees: root node not found in graph";
233
234 // 2. Pre-collect adjacency lists as node IDs (Array for O(1) access)
235 auto adj = Array<Array<size_t>>::create(n_);
236 g_.for_each_node([&](Node * p)
237 {
238 const size_t pid = node_to_id_.find(p);
240 for (auto it = typename GT::Node_Arc_Iterator(p);
241 it.has_curr(); it.next_ne())
242 {
243 auto * a = it.get_curr();
244 auto * neighbor = g_.get_connected_node(a, p);
245 neighbors.append(node_to_id_.find(neighbor));
246 }
247 adj(pid) = Array<size_t>(neighbors);
248 });
249
250 // 3. Iterative DFS to build Euler tours + parent/depth
259 for (size_t i = 0; i < n_; ++i)
260 parent_(i) = NONE;
261
262 auto visited = Array<bool>::create(n_);
263 for (size_t i = 0; i < n_; ++i)
264 visited(i) = false;
265
266 size_t sub_timer = 0;
267 size_t path_timer = 0;
268
269 struct Frame { size_t id; size_t child_idx; };
271
272 const size_t root_id = node_to_id_.find(root_);
273 visited(root_id) = true;
274 depth_(root_id) = 0;
275 parent_(root_id) = NONE;
276
277 tin_(root_id) = sub_timer;
278 flat_sub_(sub_timer) = node_values_(root_id);
279 ++sub_timer;
280
281 first_(root_id) = path_timer;
282 flat_node_(path_timer) = root_id;
283 ++path_timer;
284
285 stk.push({root_id, 0});
286
287 while (not stk.is_empty())
288 {
289 auto & fr = stk.top();
290 bool pushed = false;
291
292 while (fr.child_idx < adj(fr.id).size())
293 {
294 const size_t nid = adj(fr.id)(fr.child_idx++);
295 if (visited(nid))
296 continue;
297
298 visited(nid) = true;
299 parent_(nid) = fr.id;
300 depth_(nid) = depth_(fr.id) + 1;
301
302 tin_(nid) = sub_timer;
304 ++sub_timer;
305
308 ++path_timer;
309
310 stk.push({nid, 0});
311 pushed = true;
312 break;
313 }
314
315 if (not pushed)
316 {
317 tout_(fr.id) = sub_timer - 1;
318
319 last_(fr.id) = path_timer;
321 ++path_timer;
322
323 (void) stk.pop();
324 }
325 }
326
328 << "Gen_Mo_On_Trees: graph is not connected (not a tree)";
329
330 // 4. Binary lifting table for LCA
331 log_n_ = 1;
332 while ((static_cast<size_t>(1) << log_n_) < n_)
333 ++log_n_;
334 ++log_n_;
335
337 for (size_t i = 0; i < log_n_ * n_; ++i)
338 up_(i) = NONE;
339
340 for (size_t v = 0; v < n_; ++v)
341 up_(0 * n_ + v) = parent_(v);
342
343 for (size_t k = 1; k < log_n_; ++k)
344 for (size_t v = 0; v < n_; ++v)
345 up_(k * n_ + v) = (up_((k-1) * n_ + v) == NONE)
346 ? NONE
347 : up_((k-1) * n_ + up_((k-1) * n_ + v));
348 }
349
350 // LCA via binary lifting – O(log N)
351 size_t lca(size_t u, size_t v) const
352 {
353 if (depth_(u) < depth_(v))
354 std::swap(u, v);
355
356 const size_t diff = depth_(u) - depth_(v);
357 for (size_t k = 0; k < log_n_; ++k)
358 if ((diff >> k) & 1)
359 u = up_(k * n_ + u);
360
361 if (u == v)
362 return u;
363
364 for (int k = static_cast<int>(log_n_) - 1; k >= 0; --k)
365 if (up_(k * n_ + u) != up_(k * n_ + v))
366 {
367 u = up_(k * n_ + u);
368 v = up_(k * n_ + v);
369 }
370
371 return up_(0 * n_ + u);
372 }
373
374 // Standard Mo sweep (used for subtree queries)
377 size_t n) const
378 {
379 const size_t q = queries.size();
380 const size_t block = std::max<size_t>(
381 1, static_cast<size_t>(std::sqrt(static_cast<double>(n))));
382
383 std::sort(&queries(0), &queries(0) + q,
384 [block](const Mo_Query & a, const Mo_Query & b)
385 {
386 const size_t ba = a.l / block;
387 const size_t bb = b.l / block;
388 if (ba != bb)
389 return ba < bb;
390 return (ba & 1) ? (a.r > b.r) : (a.r < b.r);
391 });
392
393 pol_.init(data, n);
394
396
397 size_t cur_l = queries(0).l;
398 size_t cur_r = queries(0).l;
399 pol_.add(data, cur_l);
400
401 while (cur_r < queries(0).r)
402 pol_.add(data, ++cur_r);
403
404 answers(queries(0).id) = pol_.answer();
405
406 for (size_t i = 1; i < q; ++i)
407 {
408 const size_t ql = queries(i).l;
409 const size_t qr = queries(i).r;
410
411 while (cur_r < qr)
412 pol_.add(data, ++cur_r);
413
414 while (cur_l > ql)
415 pol_.add(data, --cur_l);
416
417 while (cur_r > qr)
418 pol_.remove(data, cur_r--);
419
420 while (cur_l < ql)
421 pol_.remove(data, cur_l++);
422
423 answers(queries(i).id) = pol_.answer();
424 }
425
426 return answers;
427 }
428
429 public:
430
448 : g_(g), root_(root), pol_(std::move(p))
449 {
450 build();
451 }
452
454 [[nodiscard]] size_t size() const noexcept { return n_; }
455
457 [[nodiscard]] bool is_empty() const noexcept { return n_ == 0; }
458
459 // ── Subtree queries ──────────────────────────────────────────
460
480 const Array<Node*> & query_roots) const
481 {
482 const size_t q = query_roots.size();
483 if (q == 0)
484 return Array<answer_type>();
485
487 for (size_t i = 0; i < q; ++i)
488 {
489 auto * p = node_to_id_.search(query_roots(i));
490 ah_domain_error_if(p == nullptr)
491 << "subtree_solve: query " << i << " node not in tree";
492 const size_t id = p->second;
493 queries(i) = {tin_(id), tout_(id), i};
494 }
495
496 return mo_sweep(flat_sub_, std::move(queries), n_);
497 }
498
511 std::initializer_list<Node*> il) const
512 {
513 const Array<Node*> roots(il);
514 return subtree_solve(roots);
515 }
516
517 // ── Path queries ─────────────────────────────────────────────
518
540 const Array<std::pair<Node*, Node*>> & query_pairs) const
541 {
542 const size_t q = query_pairs.size();
543 if (q == 0)
544 return Array<answer_type>();
545
546 struct Path_Query
547 {
548 size_t l, r, id, lca_id;
549 };
550
552 for (size_t i = 0; i < q; ++i)
553 {
554 auto * pu = node_to_id_.search(query_pairs(i).first);
555 auto * pv = node_to_id_.search(query_pairs(i).second);
556 ah_domain_error_if(pu == nullptr or pv == nullptr)
557 << "path_solve: query " << i << " node not in tree";
558
559 size_t u = pu->second;
560 size_t v = pv->second;
561
562 if (first_(u) > first_(v))
563 std::swap(u, v);
564
565 if (const size_t ancestor = lca(u, v); ancestor == u)
566 pqueries(i) = {first_(u), first_(v), i, NONE};
567 else
568 pqueries(i) = {last_(u), first_(v), i, ancestor};
569 }
570
571 // Snake sort
572 const size_t tour_sz = 2 * n_;
573 const size_t block = std::max<size_t>(
574 1, static_cast<size_t>(
575 std::sqrt(static_cast<double>(tour_sz))));
576
577 std::sort(&pqueries(0), &pqueries(0) + q,
578 [block](const Path_Query & a, const Path_Query & b)
579 {
580 const size_t ba = a.l / block;
581 const size_t bb = b.l / block;
582 if (ba != bb)
583 return ba < bb;
584 return (ba & 1) ? (a.r > b.r) : (a.r < b.r);
585 });
586
587 pol_.init(node_values_, n_);
588
590 auto active = Array<bool>::create(n_);
591 for (size_t i = 0; i < n_; ++i)
592 active(i) = false;
593
594 // Toggle: flip node activity and call policy add/remove
595 auto toggle = [&](const size_t pos)
596 {
597 if (const size_t nid = flat_node_(pos); active(nid))
598 {
599 pol_.remove(node_values_, nid);
600 active(nid) = false;
601 }
602 else
603 {
604 pol_.add(node_values_, nid);
605 active(nid) = true;
606 }
607 };
608
609 // Initialize window to first query
610 size_t cur_l = pqueries(0).l;
611 size_t cur_r = pqueries(0).l;
612 toggle(cur_l);
613
614 while (cur_r < pqueries(0).r)
615 toggle(++cur_r);
616
617 if (pqueries(0).lca_id != NONE)
618 {
619 pol_.add(node_values_, pqueries(0).lca_id);
620 answers(pqueries(0).id) = pol_.answer();
621 pol_.remove(node_values_, pqueries(0).lca_id);
622 }
623 else
624 answers(pqueries(0).id) = pol_.answer();
625
626 // Sweep remaining queries
627 for (size_t i = 1; i < q; ++i)
628 {
629 const size_t ql = pqueries(i).l;
630 const size_t qr = pqueries(i).r;
631
632 while (cur_r < qr) toggle(++cur_r);
633 while (cur_l > ql) toggle(--cur_l);
634 while (cur_r > qr) toggle(cur_r--);
635 while (cur_l < ql) toggle(cur_l++);
636
637 if (pqueries(i).lca_id != NONE)
638 {
639 pol_.add(node_values_, pqueries(i).lca_id);
640 answers(pqueries(i).id) = pol_.answer();
641 pol_.remove(node_values_, pqueries(i).lca_id);
642 }
643 else
644 answers(pqueries(i).id) = pol_.answer();
645 }
646
647 return answers;
648 }
649
663 std::initializer_list<std::pair<Node*, Node*>> il) const
664 {
665 const Array<std::pair<Node*, Node*>> pairs(il);
666 return path_solve(pairs);
667 }
668 };
669
670 // ================================================================
671 // Gen_Mo_On_Tree_Node — Mo on N-ary trees (Tree_Node<T>)
672 // ================================================================
673
698 template <typename T, class Policy>
699 requires MoPolicy<Policy, T>
701 {
702 public:
704 using answer_type = typename Policy::answer_type;
705
706 private:
707 static constexpr size_t NONE = ~size_t(0);
708
710 mutable Policy pol_;
711 size_t n_ = 0;
712
713 // Node <-> ID mapping
717
718 // Single-occurrence Euler tour (subtree queries, size n)
722
723 // Double-occurrence Euler tour (path queries, size 2n)
727
728 // Binary lifting for LCA
729 size_t log_n_ = 0;
732 Array<size_t> up_; // flattened [log_n_][n_]: up_(k * n_ + v)
733
734 // ── Build ──────────────────────────────────────────────────────
735
736 void build()
737 {
738 // 1. Collect nodes iteratively in preorder (no recursion).
739 n_ = 0;
740 if (root_ == nullptr)
741 return;
742
744 {
746 stk.push(root_);
747
748 while (not stk.is_empty())
749 {
750 Node * curr = stk.pop();
751 preorder.append(curr);
752 ++n_;
753
754 // Push children right-to-left so stack pops left-to-right.
756 for (Node * c = curr->get_left_child(); c != nullptr;
757 c = c->get_right_sibling())
759
760 while (not rev_children.is_empty())
761 stk.push(rev_children.pop());
762 }
763 }
764
765 if (n_ == 0)
766 return;
767
768 // 2. Assign IDs (pre-allocate OLhash for n_ entries)
771 {
773 node_to_id_.swap(tmp);
774 }
775
776 // Pre-collect adjacency as Array<Array<size_t>> for O(1) indexed access
777 auto adj = Array<Array<size_t>>::create(n_);
778 {
779 size_t next_id = 0;
780 for (auto it = preorder.get_it(); it.has_curr(); it.next_ne())
781 {
782 Node * mp = it.get_curr();
784 id_to_node_(next_id) = mp;
786 ++next_id;
787 }
788
789 // Build adjacency: children plus parent if it belongs to this rooted tree.
790 for (size_t pid = 0; pid < n_; ++pid)
791 {
792 Node * mp = id_to_node_(pid);
794
795 for (Node * c = mp->get_left_child(); c != nullptr;
796 c = c->get_right_sibling())
798
799 Node * par = mp->get_parent();
800 if (par != nullptr)
801 if (auto * pp = node_to_id_.search(par); pp != nullptr)
802 neighbors.append(pp->second);
803
804 adj(pid) = Array<size_t>(neighbors);
805 }
806 }
807
808 // 3. Iterative DFS for Euler tours + parent/depth
817 for (size_t i = 0; i < n_; ++i)
818 parent_(i) = NONE;
819
820 auto visited = Array<bool>::create(n_);
821 for (size_t i = 0; i < n_; ++i)
822 visited(i) = false;
823
824 size_t sub_timer = 0;
825 size_t path_timer = 0;
826
827 struct Frame { size_t id; size_t child_idx; };
829
830 const size_t root_id = node_to_id_.find(root_);
831 visited(root_id) = true;
832 depth_(root_id) = 0;
833 parent_(root_id) = NONE;
834
835 tin_(root_id) = sub_timer;
836 flat_sub_(sub_timer) = node_values_(root_id);
837 ++sub_timer;
838
839 first_(root_id) = path_timer;
840 flat_node_(path_timer) = root_id;
841 ++path_timer;
842
843 stk.push({root_id, 0});
844
845 while (not stk.is_empty())
846 {
847 auto & fr = stk.top();
848 bool pushed = false;
849
850 while (fr.child_idx < adj(fr.id).size())
851 {
852 const size_t nid = adj(fr.id)(fr.child_idx++);
853 if (visited(nid))
854 continue;
855
856 visited(nid) = true;
857 parent_(nid) = fr.id;
858 depth_(nid) = depth_(fr.id) + 1;
859
860 tin_(nid) = sub_timer;
862 ++sub_timer;
863
866 ++path_timer;
867
868 stk.push({nid, 0});
869 pushed = true;
870 break;
871 }
872
873 if (not pushed)
874 {
875 tout_(fr.id) = sub_timer - 1;
876
877 last_(fr.id) = path_timer;
879 ++path_timer;
880
881 (void) stk.pop();
882 }
883 }
884
886 << "Gen_Mo_On_Tree_Node: tree traversal inconsistency";
887
888 // 4. Binary lifting table for LCA
889 log_n_ = 1;
890 while ((static_cast<size_t>(1) << log_n_) < n_)
891 ++log_n_;
892 ++log_n_;
893
895 for (size_t i = 0; i < log_n_ * n_; ++i)
896 up_(i) = NONE;
897
898 for (size_t v = 0; v < n_; ++v)
899 up_(0 * n_ + v) = parent_(v);
900
901 for (size_t k = 1; k < log_n_; ++k)
902 for (size_t v = 0; v < n_; ++v)
903 up_(k * n_ + v) = (up_((k-1) * n_ + v) == NONE)
904 ? NONE
905 : up_((k-1) * n_ + up_((k-1) * n_ + v));
906 }
907
908 // LCA via binary lifting – O(log N)
909 size_t lca(size_t u, size_t v) const
910 {
911 if (depth_(u) < depth_(v))
912 std::swap(u, v);
913
914 size_t diff = depth_(u) - depth_(v);
915 for (size_t k = 0; k < log_n_; ++k)
916 if ((diff >> k) & 1)
917 u = up_(k * n_ + u);
918
919 if (u == v)
920 return u;
921
922 for (int k = static_cast<int>(log_n_) - 1; k >= 0; --k)
923 if (up_(k * n_ + u) != up_(k * n_ + v))
924 {
925 u = up_(k * n_ + u);
926 v = up_(k * n_ + v);
927 }
928
929 return up_(0 * n_ + u);
930 }
931
932 // Standard Mo sweep
935 size_t nn) const
936 {
937 const size_t q = queries.size();
938 const size_t block = std::max<size_t>(
939 1, static_cast<size_t>(std::sqrt(static_cast<double>(nn))));
940
941 std::sort(&queries(0), &queries(0) + q,
942 [block](const Mo_Query & a, const Mo_Query & b)
943 {
944 const size_t ba = a.l / block;
945 const size_t bb = b.l / block;
946 if (ba != bb)
947 return ba < bb;
948 return (ba & 1) ? (a.r > b.r) : (a.r < b.r);
949 });
950
951 pol_.init(data, nn);
952
954
955 size_t cur_l = queries(0).l;
956 size_t cur_r = queries(0).l;
957 pol_.add(data, cur_l);
958
959 while (cur_r < queries(0).r)
960 pol_.add(data, ++cur_r);
961
962 answers(queries(0).id) = pol_.answer();
963
964 for (size_t i = 1; i < q; ++i)
965 {
966 const size_t ql = queries(i).l;
967 const size_t qr = queries(i).r;
968
969 while (cur_r < qr) pol_.add(data, ++cur_r);
970 while (cur_l > ql) pol_.add(data, --cur_l);
971 while (cur_r > qr) pol_.remove(data, cur_r--);
972 while (cur_l < ql) pol_.remove(data, cur_l++);
973
974 answers(queries(i).id) = pol_.answer();
975 }
976
977 return answers;
978 }
979
980 public:
981
996 : root_(root), pol_(std::move(p))
997 {
998 ah_domain_error_if(root == nullptr)
999 << "Gen_Mo_On_Tree_Node: root is null";
1000 build();
1001 }
1002
1004 [[nodiscard]] size_t size() const noexcept { return n_; }
1005
1007 [[nodiscard]] bool is_empty() const noexcept { return n_ == 0; }
1008
1009 // ── Subtree queries ──────────────────────────────────────────
1010
1024 const Array<Node*> & query_roots) const
1025 {
1026 const size_t q = query_roots.size();
1027 if (q == 0)
1028 return Array<answer_type>();
1029
1031 for (size_t i = 0; i < q; ++i)
1032 {
1033 auto * p = node_to_id_.search(query_roots(i));
1034 ah_domain_error_if(p == nullptr)
1035 << "subtree_solve: query " << i << " node not in tree";
1036 const size_t id = p->second;
1037 queries(i) = {tin_(id), tout_(id), i};
1038 }
1039
1040 return mo_sweep(flat_sub_, std::move(queries), n_);
1041 }
1042
1055 std::initializer_list<Node*> il) const
1056 {
1057 const Array<Node*> roots(il);
1058 return subtree_solve(roots);
1059 }
1060
1061 // ── Path queries ─────────────────────────────────────────────
1062
1076 const Array<std::pair<Node*, Node*>> & query_pairs) const
1077 {
1078 const size_t q = query_pairs.size();
1079 if (q == 0)
1080 return Array<answer_type>();
1081
1082 struct Path_Query
1083 {
1084 size_t l, r, id, lca_id;
1085 };
1086
1088 for (size_t i = 0; i < q; ++i)
1089 {
1090 auto * pu = node_to_id_.search(query_pairs(i).first);
1091 auto * pv = node_to_id_.search(query_pairs(i).second);
1092 ah_domain_error_if(pu == nullptr or pv == nullptr)
1093 << "path_solve: query " << i << " node not in tree";
1094
1095 size_t u = pu->second;
1096 size_t v = pv->second;
1097
1098 if (first_(u) > first_(v))
1099 std::swap(u, v);
1100
1101 const size_t ancestor = lca(u, v);
1102
1103 if (ancestor == u)
1104 pqueries(i) = {first_(u), first_(v), i, NONE};
1105 else
1106 pqueries(i) = {last_(u), first_(v), i, ancestor};
1107 }
1108
1109 // Snake sort
1110 const size_t tour_sz = 2 * n_;
1111 const size_t block = std::max<size_t>(
1112 1, static_cast<size_t>(
1113 std::sqrt(static_cast<double>(tour_sz))));
1114
1115 std::sort(&pqueries(0), &pqueries(0) + q,
1116 [block](const Path_Query & a, const Path_Query & b)
1117 {
1118 const size_t ba = a.l / block;
1119 const size_t bb = b.l / block;
1120 if (ba != bb)
1121 return ba < bb;
1122 return (ba & 1) ? (a.r > b.r) : (a.r < b.r);
1123 });
1124
1125 pol_.init(node_values_, n_);
1126
1128 auto active = Array<bool>::create(n_);
1129 for (size_t i = 0; i < n_; ++i)
1130 active(i) = false;
1131
1132 auto toggle = [&](const size_t pos)
1133 {
1134 if (const size_t nid = flat_node_(pos); active(nid))
1135 {
1136 pol_.remove(node_values_, nid);
1137 active(nid) = false;
1138 }
1139 else
1140 {
1141 pol_.add(node_values_, nid);
1142 active(nid) = true;
1143 }
1144 };
1145
1146 size_t cur_l = pqueries(0).l;
1147 size_t cur_r = pqueries(0).l;
1148 toggle(cur_l);
1149
1150 while (cur_r < pqueries(0).r)
1151 toggle(++cur_r);
1152
1153 if (pqueries(0).lca_id != NONE)
1154 {
1155 pol_.add(node_values_, pqueries(0).lca_id);
1156 answers(pqueries(0).id) = pol_.answer();
1157 pol_.remove(node_values_, pqueries(0).lca_id);
1158 }
1159 else
1160 answers(pqueries(0).id) = pol_.answer();
1161
1162 for (size_t i = 1; i < q; ++i)
1163 {
1164 const size_t ql = pqueries(i).l;
1165 const size_t qr = pqueries(i).r;
1166
1167 while (cur_r < qr) toggle(++cur_r);
1168 while (cur_l > ql) toggle(--cur_l);
1169 while (cur_r > qr) toggle(cur_r--);
1170 while (cur_l < ql) toggle(cur_l++);
1171
1172 if (pqueries(i).lca_id != NONE)
1173 {
1174 pol_.add(node_values_, pqueries(i).lca_id);
1175 answers(pqueries(i).id) = pol_.answer();
1176 pol_.remove(node_values_, pqueries(i).lca_id);
1177 }
1178 else
1179 answers(pqueries(i).id) = pol_.answer();
1180 }
1181
1182 return answers;
1183 }
1184
1198 std::initializer_list<std::pair<Node*, Node*>> il) const
1199 {
1200 const Array<std::pair<Node*, Node*>> pairs(il);
1201 return path_solve(pairs);
1202 }
1203 };
1204
1205 // ================================================================
1206 // Convenient typedefs
1207 // ================================================================
1208
1213 template <class GT>
1217
1222 template <class GT>
1226
1231 template <class GT>
1235
1240 template <typename T>
1243
1248 template <typename T>
1251
1256 template <typename T>
1259
1260} // namespace Aleph
1261
1262# 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:522
List_Graph< Graph_Node< Node_Info >, Graph_Arc< Arc_Info > > GT
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
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.
Dynamic singly linked list with functional programming support.
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:436
Generic m-ary trees.
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:778
constexpr size_t vsize() const noexcept
Definition graph-dry.H:704
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:1482
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:4060
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.
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