Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_cartesian_tree.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
68# ifndef TPL_CARTESIAN_TREE_H
69# define TPL_CARTESIAN_TREE_H
70
71# include <cassert>
72# include <cstddef>
73# include <concepts>
74# include <initializer_list>
75# include <type_traits>
76# include <utility>
77# include <vector>
78# include <tpl_array.H>
79# include <tpl_dynList.H>
80# include <tpl_sparse_table.H>
81# include <ahFunction.H>
82# include <ah-errors.H>
83# include <ah-concepts.H>
84
85namespace Aleph
86{
117 template <typename T, class Comp>
120 {
121 public:
123 static constexpr size_t NONE = static_cast<size_t>(-1);
124
125 private:
126 Array<T> data_; // original values
127 Array<size_t> parent_; // parent[i] = parent of node i
128 Array<size_t> left_; // left[i] = left child of node i
129 Array<size_t> right_; // right[i] = right child of node i
130 size_t root_; // index of the root node
131 size_t n_; // number of elements
132
134
136 void build()
137 {
138 if (n_ == 0)
139 {
140 root_ = NONE;
141 return;
142 }
143
144 // Stack stored in a plain array — at most n elements
146 size_t top = 0; // stack size (top points to next free slot)
147
148 for (size_t i = 0; i < n_; ++i)
149 {
150 size_t last_popped = NONE;
151
152 // Pop while i is strictly better than stack top (stable on ties)
153 while (top > 0 and comp_(data_(i), data_(stk(top - 1))))
154 {
155 last_popped = stk(top - 1);
156 --top;
157 }
158
159 // The last popped node becomes the left child of i
160 left_(i) = last_popped;
161 if (last_popped != NONE)
162 parent_(last_popped) = i;
163
164 // i becomes right child of the current stack top
165 if (top > 0)
166 {
167 right_(stk(top - 1)) = i;
168 parent_(i) = stk(top - 1);
169 }
170 else
171 parent_(i) = NONE;
172
173 stk(top++) = i;
174 }
175
176 root_ = stk(0); // the bottom of the stack is the root
177 }
178
181 {
185 for (size_t i = 0; i < n_; ++i)
186 {
187 parent_(i) = NONE;
188 left_(i) = NONE;
189 right_(i) = NONE;
190 }
191 build();
192 }
193
194 public:
196 using Item_Type = T;
197
203 : data_(values), root_(NONE), n_(values.size()), comp_(c)
204 {
206 }
207
212 Gen_Cartesian_Tree(const std::vector<T> & values, Comp c = Comp())
213 : data_(Array<T>::create(values.size())), root_(NONE),
214 n_(values.size()), comp_(c)
215 {
216 for (size_t i = 0; i < n_; ++i)
217 data_(i) = values[i];
219 }
220
225 Gen_Cartesian_Tree(std::initializer_list<T> il, Comp c = Comp())
226 : data_(Array<T>::create(il.size())), root_(NONE),
227 n_(il.size()), comp_(c)
228 {
229 size_t i = 0;
230 for (auto it = il.begin(); it != il.end(); ++it)
231 data_(i++) = *it;
233 }
234
240 : data_(Array<T>::create(values.size())), root_(NONE),
241 n_(values.size()), comp_(c)
242 {
243 size_t i = 0;
244 for (auto it = values.get_it(); it.has_curr(); it.next_ne())
245 data_(i++) = it.get_curr();
247 }
248
254 Gen_Cartesian_Tree(const size_t num, const T & init, Comp c = Comp())
255 : data_(Array<T>::create(num)), root_(NONE), n_(num), comp_(c)
256 {
257 for (size_t i = 0; i < n_; ++i)
258 data_(i) = init;
260 }
261
264
267
271
275
279 [[nodiscard]] constexpr size_t root() const noexcept { return root_; }
280
284 size_t left_child(const size_t i) const
285 {
287 << "Gen_Cartesian_Tree::left_child: i=" << i << " >= n=" << n_;
288 return left_(i);
289 }
290
294 size_t right_child(const size_t i) const
295 {
297 << "Gen_Cartesian_Tree::right_child: i=" << i << " >= n=" << n_;
298 return right_(i);
299 }
300
304 size_t parent_of(const size_t i) const
305 {
307 << "Gen_Cartesian_Tree::parent_of: i=" << i << " >= n=" << n_;
308 return parent_(i);
309 }
310
314 const T &data_at(const size_t i) const
315 {
317 << "Gen_Cartesian_Tree::data_at: i=" << i << " >= n=" << n_;
318 return data_(i);
319 }
320
322 [[nodiscard]] constexpr size_t size() const noexcept { return n_; }
323
325 [[nodiscard]] constexpr bool is_empty() const noexcept { return n_ == 0; }
326
330 bool is_leaf(const size_t i) const
331 {
333 << "Gen_Cartesian_Tree::is_leaf: i=" << i << " >= n=" << n_;
334 return left_(i) == NONE and right_(i) == NONE;
335 }
336
338 bool is_root(const size_t i) const
339 {
341 << "Gen_Cartesian_Tree::is_root: i=" << i << " >= n=" << n_;
342 return i == root_;
343 }
344
355 [[nodiscard]] size_t height() const
356 {
357 if (n_ == 0)
358 return 0;
359
360 size_t max_depth = 0;
361
362 // DFS with explicit stack: (node, depth)
363 struct Entry
364 {
365 size_t node;
366 size_t depth;
367 };
369 size_t top = 0;
370 stk(top++) = {root_, 1};
371
372 while (top > 0)
373 {
374 auto [node, depth] = stk(--top);
375 if (depth > max_depth)
376 max_depth = depth;
377 if (right_(node) != NONE)
378 stk(top++) = {right_(node), depth + 1};
379 if (left_(node) != NONE)
380 stk(top++) = {left_(node), depth + 1};
381 }
382
383 return max_depth;
384 }
385
400 {
401 if (n_ == 0)
402 return {};
403
404 auto result = Array<size_t>::create(n_);
405 size_t idx = 0;
406
407 // Iterative inorder with explicit stack
409 size_t top = 0;
410 size_t curr = root_;
411
412 while (curr != NONE or top > 0)
413 {
414 while (curr != NONE)
415 {
416 stk(top++) = curr;
417 curr = left_(curr);
418 }
419 curr = stk(--top);
420 result(idx++) = curr;
421 curr = right_(curr);
422 }
423
424 return result;
425 }
426
440 {
441 auto ret = Array<T>::create(n_);
442 for (size_t i = 0; i < n_; ++i)
443 ret(i) = data_(i);
444 return ret;
445 }
446
449 noexcept(noexcept(data_.swap(other.data_)) &&
450 noexcept(parent_.swap(other.parent_)) &&
451 noexcept(left_.swap(other.left_)) &&
452 noexcept(right_.swap(other.right_)) &&
453 noexcept(std::swap(root_, other.root_)) &&
454 noexcept(std::swap(n_, other.n_)) &&
455 std::is_nothrow_swappable_v<Comp>)
456 {
457 data_.swap(other.data_);
458 parent_.swap(other.parent_);
459 left_.swap(other.left_);
460 right_.swap(other.right_);
461 std::swap(root_, other.root_);
462 std::swap(n_, other.n_);
463 std::swap(comp_, other.comp_);
464 }
465 };
466
471 template <std::totally_ordered T>
473 : public Gen_Cartesian_Tree<T, Aleph::less<T>>
474 {
476 using Base::Base;
477 };
478
483 template <std::totally_ordered T>
485 : public Gen_Cartesian_Tree<T, Aleph::greater<T>>
486 {
488 using Base::Base;
489 };
490
491
492 // ================================================================
493 // Gen_Euler_Tour_LCA — LCA in O(1) via Euler Tour + Sparse Table
494 // ================================================================
495
519 template <typename T, class Comp>
522 {
525 {
526 size_t depth;
527 size_t node;
528 };
529
532 {
533 constexpr DepthEntry operator()(const DepthEntry & a,
534 const DepthEntry & b) const noexcept
535 {
536 return a.depth <= b.depth ? a : b;
537 }
538 };
539
541 Array<size_t> euler_; // euler tour: 2n-1 node indices
542 Array<size_t> depth_arr_; // depth at each euler tour position
543 Array<size_t> first_; // first_[node] = first position in euler
544 Array<size_t> node_depth_; // depth of each node in the tree
547
550 {
551 const size_t n = tree_.size();
552 if (n == 0)
553 return;
554
555 constexpr size_t NONE = Gen_Cartesian_Tree<T, Comp>::NONE;
556
557 euler_size_ = 2 * n - 1;
562
563 for (size_t i = 0; i < n; ++i)
564 first_(i) = NONE;
565
566 // Stack entries: (node, phase, depth, cached children)
567 // phase 0: first visit — record euler, push left child
568 // phase 1: back from left — if left existed, record euler;
569 // push right child
570 // phase 2: back from right — if right existed, record euler;
571 // pop
572 struct Frame
573 {
574 size_t node;
575 int phase;
576 size_t depth;
577 size_t left;
578 size_t right;
579 };
580 auto make_frame = [this](const size_t node, const size_t depth) -> Frame
581 {
582 return {node, 0, depth, tree_.left_child(node), tree_.right_child(node)};
583 };
584 auto stk = Array<Frame>::create(n);
585 size_t top = 0;
586 size_t eidx = 0;
587
588 stk(top++) = make_frame(tree_.root(), 0);
589
590 while (top > 0)
591 {
592 if (auto & frame = stk(top - 1); frame.phase == 0)
593 {
594 // First visit — always record
595 euler_(eidx) = frame.node;
596 depth_arr_(eidx) = frame.depth;
597 node_depth_(frame.node) = frame.depth;
598 first_(frame.node) = eidx;
599 ++eidx;
600 frame.phase = 1;
601
602 if (frame.left != NONE)
603 stk(top++) = make_frame(frame.left, frame.depth + 1);
604 }
605 else if (frame.phase == 1)
606 {
607 // Back from left subtree
608 if (frame.left != NONE)
609 {
610 // We actually returned from left child — record again
611 euler_(eidx) = frame.node;
612 depth_arr_(eidx) = frame.depth;
613 ++eidx;
614 }
615 frame.phase = 2;
616
617 if (frame.right != NONE)
618 stk(top++) = make_frame(frame.right, frame.depth + 1);
619 }
620 else
621 {
622 // Back from right subtree
623 if (frame.right != NONE)
624 {
625 // We actually returned from right child — record again
626 euler_(eidx) = frame.node;
627 depth_arr_(eidx) = frame.depth;
628 ++eidx;
629 }
630 --top;
631 }
632 }
633
634 // Euler tour length is exactly 2*n-1 for any non-empty binary tree.
636 }
637
640 {
641 if (euler_size_ == 0)
642 return;
643
645 for (size_t i = 0; i < euler_size_; ++i)
646 entries(i) = {depth_arr_(i), euler_(i)};
647
649 }
650
651 public:
656 Gen_Euler_Tour_LCA(const Array<T> & values, Comp c = Comp())
657 : tree_(values, c), sparse_(0, DepthEntry{0, 0}), euler_size_(0)
658 {
661 }
662
664 Gen_Euler_Tour_LCA(const std::vector<T> & values, Comp c = Comp())
665 : tree_(values, c), sparse_(0, DepthEntry{0, 0}), euler_size_(0)
666 {
669 }
670
672 Gen_Euler_Tour_LCA(std::initializer_list<T> il, Comp c = Comp())
673 : tree_(il, c), sparse_(0, DepthEntry{0, 0}), euler_size_(0)
674 {
677 }
678
680 Gen_Euler_Tour_LCA(const DynList<T> & values, Comp c = Comp())
681 : tree_(values, c), sparse_(0, DepthEntry{0, 0}), euler_size_(0)
682 {
685 }
686
688 Gen_Euler_Tour_LCA(const size_t num, const T & init, Comp c = Comp())
689 : tree_(num, init, c), sparse_(0, DepthEntry{0, 0}), euler_size_(0)
690 {
693 }
694
703 size_t lca(const size_t u, const size_t v) const
704 {
705 const size_t n = tree_.size();
707 << "Gen_Euler_Tour_LCA::lca: u=" << u << " >= n=" << n;
709 << "Gen_Euler_Tour_LCA::lca: v=" << v << " >= n=" << n;
710
711 size_t l = first_(u);
712 size_t r = first_(v);
713 if (l > r)
714 std::swap(l, r);
715
716 return sparse_.query(l, r).node;
717 }
718
722 size_t depth_of(const size_t u) const
723 {
725 << "Gen_Euler_Tour_LCA::depth_of: u=" << u << " >= n=" << tree_.size();
726 return node_depth_(u);
727 }
728
733 size_t distance(const size_t u, const size_t v) const
734 {
735 const size_t ancestor = lca(u, v);
736 return node_depth_(u) + node_depth_(v) - 2 * node_depth_(ancestor);
737 }
738
740 [[nodiscard]] constexpr size_t size() const noexcept
741 {
742 return tree_.size();
743 }
744
746 [[nodiscard]] constexpr bool is_empty() const noexcept
747 {
748 return tree_.is_empty();
749 }
750
753 {
754 return tree_;
755 }
756
759 {
761 for (size_t i = 0; i < euler_size_; ++i)
762 ret(i) = euler_(i);
763 return ret;
764 }
765
768 {
769 return euler_size_;
770 }
771 };
772
777 template <std::totally_ordered T>
779 : public Gen_Euler_Tour_LCA<T, Aleph::less<T>>
780 {
782 using Base::Base;
783 };
784
789 template <std::totally_ordered T>
791 : public Gen_Euler_Tour_LCA<T, Aleph::greater<T>>
792 {
794 using Base::Base;
795 };
796
797
798 // ================================================================
799 // Gen_Cartesian_Tree_RMQ — O(1) RMQ via Cartesian Tree + LCA
800 // ================================================================
801
827 template <typename T, class Comp>
830 {
832
833 public:
835 using Item_Type = T;
836
840
842 Gen_Cartesian_Tree_RMQ(const std::vector<T> & values, Comp c = Comp())
843 : lca_(values, c) {}
844
846 Gen_Cartesian_Tree_RMQ(std::initializer_list<T> il, Comp c = Comp())
847 : lca_(il, c) {}
848
852
854 Gen_Cartesian_Tree_RMQ(const size_t num, const T & init,
855 Comp c = Comp())
856 : lca_(num, init, c) {}
857
867 T query(const size_t l, const size_t r) const
868 {
870 << "Gen_Cartesian_Tree_RMQ::query: l=" << l << " > r=" << r;
872 << "Gen_Cartesian_Tree_RMQ::query: r=" << r << " >= n=" << lca_.size();
873
874 return lca_.tree().data_at(lca_.lca(l, r));
875 }
876
886 size_t query_idx(const size_t l, const size_t r) const
887 {
889 << "Gen_Cartesian_Tree_RMQ::query_idx: l=" << l << " > r=" << r;
891 << "Gen_Cartesian_Tree_RMQ::query_idx: r=" << r << " >= n=" << lca_.size();
892
893 return lca_.lca(l, r);
894 }
895
902 T get(const size_t i) const
903 {
904 return lca_.tree().data_at(i);
905 }
906
908 [[nodiscard]] constexpr size_t size() const noexcept
909 {
910 return lca_.size();
911 }
912
914 [[nodiscard]] constexpr bool is_empty() const noexcept
915 {
916 return lca_.is_empty();
917 }
918
921 {
922 return lca_.tree().values();
923 }
924
927 {
928 return lca_;
929 }
930 };
931
936 template <std::totally_ordered T>
938 : public Gen_Cartesian_Tree_RMQ<T, Aleph::less<T>>
939 {
941 using Base::Base;
942 };
943
948 template <std::totally_ordered T>
950 : public Gen_Cartesian_Tree_RMQ<T, Aleph::greater<T>>
951 {
953 using Base::Base;
954 };
955} // end namespace Aleph
956
957# endif /* TPL_CARTESIAN_TREE_H */
C++20 concepts for constraining comparison functors.
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:579
Standard functor implementations and comparison objects.
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
void swap(Array &s) noexcept
Swap this with s
Definition tpl_array.H:227
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
O(1) static range queries via the Cartesian Tree reduction.
constexpr size_t size() const noexcept
Number of elements.
T get(const size_t i) const
Retrieve the value at position i in O(1).
const Gen_Euler_Tour_LCA< T, Comp > & lca_engine() const noexcept
Const reference to the internal LCA engine.
Array< T > values() const
Copy of the original values.
Gen_Cartesian_Tree_RMQ(const DynList< T > &values, Comp c=Comp())
Construct from a DynList<T>.
Gen_Cartesian_Tree_RMQ(const size_t num, const T &init, Comp c=Comp())
Construct with num elements all equal to init.
Gen_Cartesian_Tree_RMQ(const std::vector< T > &values, Comp c=Comp())
Construct from a std::vector<T>.
Gen_Cartesian_Tree_RMQ(std::initializer_list< T > il, Comp c=Comp())
Construct from an initializer_list<T>.
Gen_Cartesian_Tree_RMQ(const Array< T > &values, Comp c=Comp())
Construct from an Array<T>.
T query(const size_t l, const size_t r) const
Range query over [l, r] in O(1).
Gen_Euler_Tour_LCA< T, Comp > lca_
T Item_Type
The type of the element.
size_t query_idx(const size_t l, const size_t r) const
Return the index of the optimal element in a[l..r].
constexpr bool is_empty() const noexcept
True if empty.
Explicit Cartesian Tree built in O(n) with a monotonic stack.
void swap(Gen_Cartesian_Tree &other) noexcept(noexcept(data_.swap(other.data_)) &&noexcept(parent_.swap(other.parent_)) &&noexcept(left_.swap(other.left_)) &&noexcept(right_.swap(other.right_)) &&noexcept(std::swap(root_, other.root_)) &&noexcept(std::swap(n_, other.n_)) &&std::is_nothrow_swappable_v< Comp >)
Swap with other in O(1).
Gen_Cartesian_Tree(std::initializer_list< T > il, Comp c=Comp())
Construct from an initializer_list<T>.
Array< size_t > inorder() const
Inorder traversal of the tree.
T Item_Type
The type of the element stored in the tree.
constexpr size_t root() const noexcept
Index of the root node.
static constexpr size_t NONE
Sentinel value for absent parent/child links.
Array< T > values() const
Copy of the original data array.
const T & data_at(const size_t i) const
Value at node i.
size_t left_child(const size_t i) const
Left child of node i.
void init_and_build()
Initialize arrays of size n with NONE and build.
bool is_leaf(const size_t i) const
True if node i is a leaf (no children).
Gen_Cartesian_Tree(const std::vector< T > &values, Comp c=Comp())
Construct from a std::vector<T>.
Gen_Cartesian_Tree(const Gen_Cartesian_Tree &)=default
Copy constructor.
constexpr size_t size() const noexcept
Number of nodes.
Gen_Cartesian_Tree & operator=(const Gen_Cartesian_Tree &)=default
Copy assignment operator.
size_t parent_of(const size_t i) const
Parent of node i.
Gen_Cartesian_Tree(const Array< T > &values, Comp c=Comp())
Construct from an Array<T>.
Gen_Cartesian_Tree(const size_t num, const T &init, Comp c=Comp())
Construct with num elements all equal to init.
size_t right_child(const size_t i) const
Right child of node i.
void build()
Build the Cartesian Tree using a monotonic stack in O(n).
bool is_root(const size_t i) const
True if node i is the root.
constexpr bool is_empty() const noexcept
True if the tree is empty.
Gen_Cartesian_Tree(const DynList< T > &values, Comp c=Comp())
Construct from a DynList<T>.
size_t height() const
Height of the tree (longest root-to-leaf path).
Gen_Cartesian_Tree(Gen_Cartesian_Tree &&) noexcept(std::is_nothrow_move_constructible_v< Array< T > > and std::is_nothrow_move_constructible_v< Comp >)=default
Lowest Common Ancestor queries in O(1) via Euler Tour reduction to RMQ on a Cartesian Tree.
Gen_Euler_Tour_LCA(std::initializer_list< T > il, Comp c=Comp())
Construct from an initializer_list<T>.
size_t euler_tour_size() const noexcept
Size of the Euler Tour (should be 2n-1 for n > 0).
Gen_Euler_Tour_LCA(const Array< T > &values, Comp c=Comp())
Construct from an Array<T>.
constexpr size_t size() const noexcept
Number of nodes.
void build_sparse_table()
Build the Sparse Table over the depth entries.
Gen_Euler_Tour_LCA(const std::vector< T > &values, Comp c=Comp())
Construct from a std::vector<T>.
const Gen_Cartesian_Tree< T, Comp > & tree() const noexcept
Const reference to the internal Cartesian Tree.
size_t depth_of(const size_t u) const
Depth of node u in the Cartesian Tree.
Gen_Euler_Tour_LCA(const size_t num, const T &init, Comp c=Comp())
Construct with num elements all equal to init.
Gen_Euler_Tour_LCA(const DynList< T > &values, Comp c=Comp())
Construct from a DynList<T>.
constexpr bool is_empty() const noexcept
True if empty.
size_t lca(const size_t u, const size_t v) const
Lowest Common Ancestor of nodes u and v in O(1).
size_t distance(const size_t u, const size_t v) const
Distance between nodes u and v in the tree.
Gen_Cartesian_Tree< T, Comp > tree_
Array< size_t > euler_tour() const
Copy of the Euler Tour array (for inspection/debugging).
Gen_Sparse_Table< DepthEntry, DepthMinOp > sparse_
void build_euler_tour()
Build Euler Tour iteratively using an explicit stack with phases.
Sparse Table over an arbitrary associative and idempotent binary operation.
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
Strict weak ordering constraint for BST comparators.
Definition ah-concepts.H:84
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.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
static std::atomic< bool > init
Definition hash-fct.C:53
STL namespace.
Range minimum queries via Cartesian Tree.
Range maximum queries via Cartesian Tree.
Cartesian Tree for min-heap (range minimum).
LCA on a min-heap Cartesian Tree.
Entry for the depth-based Sparse Table: (depth, euler_node_index).
Min-op on DepthEntry: compares by depth.
constexpr DepthEntry operator()(const DepthEntry &a, const DepthEntry &b) const noexcept
Cartesian Tree for max-heap (range maximum).
LCA on a max-heap Cartesian Tree.
gsl_rng * r
Dynamic array container with automatic resizing.
Alias for htlist.H (DynList implementation).
Sparse Table for static range queries in O(1).
DynList< int > l