Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
cartesian_tree_example.cc
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
58# include <tpl_cartesian_tree.H>
59# include <tpl_sparse_table.H>
60
61# include <iostream>
62# include <iomanip>
63# include <chrono>
64# include <random>
65# include <vector>
66
67using namespace Aleph;
68
69// ================================================================
70// SCENARIO 1 — El Arbol Genealogico de los Datos
71// ================================================================
72
73static void scenario_1()
74{
75 std::cout << "\n"
76 "========================================================\n"
77 " SCENARIO 1: El Arbol Genealogico de los Datos\n"
78 "========================================================\n\n";
79
80 // Ages of people in a family line
81 Cartesian_Tree<int> ct = {45, 23, 67, 12, 56, 34, 78};
82
83 std::cout << "Array of ages: {45, 23, 67, 12, 56, 34, 78}\n\n";
84
85 std::cout << "Cartesian Tree structure (min-heap):\n";
86 std::cout << " Root: index " << ct.root()
87 << " (age " << ct.data_at(ct.root()) << ")\n\n";
88
89 std::cout << std::setw(8) << "Index" << std::setw(8) << "Age"
90 << std::setw(10) << "Parent" << std::setw(10) << "Left"
91 << std::setw(10) << "Right" << std::setw(8) << "Leaf?"
92 << "\n";
93 std::cout << std::string(54, '-') << "\n";
94
95 for (size_t i = 0; i < ct.size(); ++i)
96 {
97 auto fmt = [](size_t v) -> std::string {
98 return v == Cartesian_Tree<int>::NONE ? "-" : std::to_string(v);
99 };
100 std::cout << std::setw(8) << i
101 << std::setw(8) << ct.data_at(i)
102 << std::setw(10) << fmt(ct.parent_of(i))
103 << std::setw(10) << fmt(ct.left_child(i))
104 << std::setw(10) << fmt(ct.right_child(i))
105 << std::setw(8) << (ct.is_leaf(i) ? "yes" : "no")
106 << "\n";
107 }
108
109 std::cout << "\nTree height: " << ct.height() << "\n";
110
111 // Verify inorder = original order
112 auto io = ct.inorder();
113 std::cout << "\nInorder traversal: {";
114 for (size_t i = 0; i < io.size(); ++i)
115 std::cout << (i ? ", " : "") << io(i);
116 std::cout << "}\n";
117
118 bool inorder_ok = true;
119 for (size_t i = 0; i < io.size(); ++i)
120 if (io(i) != i) { inorder_ok = false; break; }
121 std::cout << "Inorder = {0, 1, ..., n-1}? "
122 << (inorder_ok ? "YES" : "NO") << "\n";
123}
124
125
126// ================================================================
127// SCENARIO 2 — Ancestros Comunes en el Linaje
128// ================================================================
129
130static void scenario_2()
131{
132 std::cout << "\n"
133 "========================================================\n"
134 " SCENARIO 2: Ancestros Comunes en el Linaje\n"
135 "========================================================\n\n";
136
137 Euler_Tour_LCA<int> lca = {45, 23, 67, 12, 56, 34, 78};
138
139 std::cout << "Array: {45, 23, 67, 12, 56, 34, 78}\n\n";
140
141 // Show the Euler Tour
142 auto euler = lca.euler_tour();
143 std::cout << "Euler Tour (" << lca.euler_tour_size() << " entries):\n ";
144 for (size_t i = 0; i < euler.size(); ++i)
145 std::cout << (i ? ", " : "") << euler(i);
146 std::cout << "\n\n";
147
148 // Show depths
149 std::cout << "Node depths:\n";
150 for (size_t i = 0; i < lca.size(); ++i)
151 std::cout << " Node " << i << " (value "
152 << lca.tree().data_at(i) << "): depth "
153 << lca.depth_of(i) << "\n";
154
155 // Query some LCAs
156 std::cout << "\nLCA queries:\n";
157 auto show_lca = [&](size_t u, size_t v) {
158 size_t a = lca.lca(u, v);
159 std::cout << " LCA(" << u << ", " << v << ") = " << a
160 << " (value " << lca.tree().data_at(a) << ")"
161 << " distance = " << lca.distance(u, v) << "\n";
162 };
163
164 show_lca(0, 2); // siblings under node 1
165 show_lca(0, 4); // across root
166 show_lca(4, 6); // right subtree
167 show_lca(1, 5); // different subtrees
168 show_lca(3, 3); // self
169}
170
171
172// ================================================================
173// SCENARIO 3 — RMQ sin Trucos: de Arbol a Respuestas O(1)
174// ================================================================
175
176static void scenario_3()
177{
178 std::cout << "\n"
179 "========================================================\n"
180 " SCENARIO 3: RMQ sin Trucos: de Arbol a Respuestas O(1)\n"
181 "========================================================\n\n";
182
183 std::vector<int> data = {5, 2, 4, 7, 1, 3, 6, 8, 0, 9};
184 std::cout << "Array: {5, 2, 4, 7, 1, 3, 6, 8, 0, 9}\n\n";
185
188
189 // Compare queries
190 std::cout << "Comparing Cartesian Tree RMQ vs Sparse Table:\n\n";
191 std::cout << std::setw(12) << "Range"
192 << std::setw(12) << "CT-RMQ"
193 << std::setw(12) << "Sparse"
194 << std::setw(10) << "Match?"
195 << "\n";
196 std::cout << std::string(46, '-') << "\n";
197
198 auto test_range = [&](size_t l, size_t r) {
199 int ct_val = ct_rmq.query(l, r);
200 int sp_val = sparse.query(l, r);
201 std::string range = "[" + std::to_string(l) + "," + std::to_string(r) + "]";
202 std::cout << std::setw(12) << range
203 << std::setw(12) << ct_val
204 << std::setw(12) << sp_val
205 << std::setw(10) << (ct_val == sp_val ? "OK" : "FAIL")
206 << "\n";
207 };
208
209 test_range(0, 3);
210 test_range(2, 6);
211 test_range(0, 9);
212 test_range(4, 4);
213 test_range(7, 9);
214 test_range(1, 8);
215
216 std::cout << "\nquery_idx(2, 6) = " << ct_rmq.query_idx(2, 6)
217 << " (value " << ct_rmq.get(ct_rmq.query_idx(2, 6)) << ")\n";
218}
219
220
221// ================================================================
222// SCENARIO 4 — El Circulo Completo: RMQ <-> LCA
223// ================================================================
224
225static void scenario_4()
226{
227 std::cout << "\n"
228 "========================================================\n"
229 " SCENARIO 4: El Circulo Completo: RMQ <-> LCA\n"
230 "========================================================\n\n";
231
232 constexpr size_t N = 100000;
233 constexpr size_t Q = 500000;
234
235 std::mt19937 rng(42);
236 std::uniform_int_distribution<int> dist(-100000, 100000);
237
238 std::vector<int> data(N);
239 for (auto & x : data)
240 x = dist(rng);
241
242 std::cout << "N = " << N << " elements, Q = " << Q << " queries\n\n";
243
244 // Build Cartesian Tree RMQ
245 auto t0 = std::chrono::high_resolution_clock::now();
247 auto t1 = std::chrono::high_resolution_clock::now();
248 double ct_build_ms = std::chrono::duration<double, std::milli>(t1 - t0).count();
249
250 // Build Sparse Table
251 t0 = std::chrono::high_resolution_clock::now();
253 t1 = std::chrono::high_resolution_clock::now();
254 double sp_build_ms = std::chrono::duration<double, std::milli>(t1 - t0).count();
255
256 std::cout << "Build times:\n";
257 std::cout << " Cartesian Tree RMQ: " << std::fixed << std::setprecision(2)
258 << ct_build_ms << " ms\n";
259 std::cout << " Sparse Table: " << sp_build_ms << " ms\n\n";
260
261 // Generate random queries
262 std::uniform_int_distribution<size_t> idx_dist(0, N - 1);
263 std::vector<std::pair<size_t, size_t>> queries(Q);
264 for (auto & [l, r] : queries)
265 {
266 l = idx_dist(rng);
267 r = idx_dist(rng);
268 if (l > r)
269 std::swap(l, r);
270 }
271
272 // Time Cartesian Tree RMQ queries
273 t0 = std::chrono::high_resolution_clock::now();
274 volatile int sink = 0;
275 for (auto & [l, r] : queries)
276 sink = ct_rmq.query(l, r);
277 t1 = std::chrono::high_resolution_clock::now();
278 double ct_query_ms = std::chrono::duration<double, std::milli>(t1 - t0).count();
279
280 // Time Sparse Table queries
281 t0 = std::chrono::high_resolution_clock::now();
282 for (auto & [l, r] : queries)
283 sink = sparse.query(l, r);
284 t1 = std::chrono::high_resolution_clock::now();
285 double sp_query_ms = std::chrono::duration<double, std::milli>(t1 - t0).count();
286
287 std::cout << "Query times (" << Q << " queries):\n";
288 std::cout << " Cartesian Tree RMQ: " << ct_query_ms << " ms\n";
289 std::cout << " Sparse Table: " << sp_query_ms << " ms\n\n";
290
291 // Verify equivalence: RMQ(l,r) = data_at(LCA(l,r))
292 std::cout << "Verifying RMQ(l,r) = data[LCA(l,r)] for first 10000 queries... ";
293 bool all_ok = true;
294 const auto & lca_engine = ct_rmq.lca_engine();
295 for (size_t i = 0; i < std::min<size_t>(10000, Q); ++i)
296 {
297 auto [l, r] = queries[i];
298 size_t ancestor = lca_engine.lca(l, r);
299 int via_lca = lca_engine.tree().data_at(ancestor);
300 int via_rmq = ct_rmq.query(l, r);
301 int via_sparse = sparse.query(l, r);
302 if (via_lca != via_rmq || via_rmq != via_sparse)
303 {
304 all_ok = false;
305 break;
306 }
307 }
308 std::cout << (all_ok ? "ALL MATCH" : "MISMATCH FOUND") << "\n\n";
309
310 std::cout << "The circle is complete:\n"
311 << " Array -> Cartesian Tree -> Euler Tour -> "
312 "Sparse Table -> O(1) LCA -> O(1) RMQ\n"
313 << " Confirming: RMQ and LCA are equivalent problems.\n";
314
315 (void)sink;
316}
317
318
319int main()
320{
321 scenario_1();
322 scenario_2();
323 scenario_3();
324 scenario_4();
325
326 std::cout << "\nAll scenarios completed successfully.\n";
327 return 0;
328}
static void scenario_3()
static void scenario_1()
static void scenario_4()
static void scenario_2()
constexpr size_t root() const noexcept
Index of the root node.
const T & data_at(const size_t i) const
Value at node i.
size_t euler_tour_size() const noexcept
Size of the Euler Tour (should be 2n-1 for n > 0).
constexpr size_t size() const noexcept
Number of nodes.
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.
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.
Array< size_t > euler_tour() const
Copy of the Euler Tour array (for inspection/debugging).
static mt19937 rng
#define N
Definition fib.C:294
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
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.
Container< T > range(const T start, const T end, const T step=1)
Generate a range of values [start, end] with a given step.
Range minimum queries via Cartesian Tree.
Cartesian Tree for min-heap (range minimum).
LCA on a min-heap Cartesian Tree.
Sparse Table for range minimum queries.
gsl_rng * r
Cartesian Tree, LCA via Euler Tour, and RMQ via Cartesian Tree.
Sparse Table for static range queries in O(1).
DynList< int > l