Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
link_cut_tree_test.cc
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
41#include <algorithm>
42#include <chrono>
43#include <numeric>
44#include <random>
45#include <vector>
46
47#include <gtest/gtest.h>
48
49#include <tpl_link_cut_tree.H>
51
52using namespace Aleph;
53using namespace testing;
54
55// ===================================================================
56// A. Structural correctness — connectivity-only Link_Cut_Tree
57// ===================================================================
58
60{
61protected:
63};
64
66{
67 auto * x = lct.make_vertex(42);
68 EXPECT_EQ(lct.find_root(x), x);
69 EXPECT_TRUE(lct.connected(x, x));
70 EXPECT_EQ(lct.size(), 1u);
71}
72
74{
77
78 auto * u1 = lct1.make_vertex(1);
79 auto * u2 = lct2.make_vertex(2);
80
81 EXPECT_THROW(lct1.destroy_vertex(u2), std::domain_error);
82 EXPECT_EQ(lct1.find_root(u1), u1);
83 EXPECT_EQ(lct2.find_root(u2), u2);
84}
85
87{
88 auto * u = lct.make_vertex(1);
89 auto * v = lct.make_vertex(2);
90
91 EXPECT_FALSE(lct.connected(u, v));
92
93 lct.link(u, v);
94 EXPECT_TRUE(lct.connected(u, v));
95 EXPECT_EQ(lct.find_root(u), lct.find_root(v));
96 EXPECT_EQ(lct.path_size(u, v), 2u);
97}
98
100{
101 auto * u = lct.make_vertex(1);
102 auto * v = lct.make_vertex(2);
103
104 lct.link(u, v);
105 EXPECT_TRUE(lct.connected(u, v));
106
107 lct.cut(u, v);
108 EXPECT_FALSE(lct.connected(u, v));
109}
110
112{
113 constexpr int N = 10;
114 std::vector<Link_Cut_Tree::Node *> nd(N);
115 for (int i = 0; i < N; ++i)
116 nd[i] = lct.make_vertex(i);
117
118 for (int i = 0; i + 1 < N; ++i)
119 lct.link(nd[i], nd[i + 1]);
120
121 for (int i = 0; i < N; ++i)
122 for (int j = i; j < N; ++j)
123 {
124 EXPECT_TRUE(lct.connected(nd[i], nd[j]));
125 EXPECT_EQ(lct.path_size(nd[i], nd[j]),
126 static_cast<size_t>(j - i + 1));
127 }
128}
129
131{
132 constexpr int N = 6;
133 std::vector<Link_Cut_Tree::Node *> nd(N);
134 for (int i = 0; i < N; ++i)
135 nd[i] = lct.make_vertex(i);
136
137 // path: 0 - 1 - 2 - 3 - 4 - 5
138 for (int i = 0; i + 1 < N; ++i)
139 lct.link(nd[i], nd[i + 1]);
140
141 // cut edge (2,3)
142 lct.cut(nd[2], nd[3]);
143 EXPECT_TRUE(lct.connected(nd[0], nd[2]));
144 EXPECT_TRUE(lct.connected(nd[3], nd[5]));
145 EXPECT_FALSE(lct.connected(nd[0], nd[5]));
146
147 // re-link
148 lct.link(nd[2], nd[3]);
149 EXPECT_TRUE(lct.connected(nd[0], nd[5]));
150}
151
153{
154 auto * center = lct.make_vertex(0);
155 constexpr int N = 8;
156 std::vector<Link_Cut_Tree::Node *> leaves(N);
157 for (int i = 0; i < N; ++i)
158 {
159 leaves[i] = lct.make_vertex(i + 1);
160 lct.link(leaves[i], center);
161 }
162
163 for (int i = 0; i < N; ++i)
164 EXPECT_TRUE(lct.connected(leaves[i], center));
165
166 for (int i = 0; i < N; ++i)
167 for (int j = i + 1; j < N; ++j)
168 EXPECT_TRUE(lct.connected(leaves[i], leaves[j]));
169
170 // cut each leaf
171 for (int i = 0; i < N; ++i)
172 {
173 lct.cut(leaves[i], center);
174 EXPECT_FALSE(lct.connected(leaves[i], center));
175 }
176}
177
178// ===================================================================
179// B. Rerooting (make_root)
180// ===================================================================
181
183{
184 // path 0-1-2-3-4
185 constexpr int N = 5;
186 std::vector<Link_Cut_Tree::Node *> nd(N);
187 for (int i = 0; i < N; ++i)
188 nd[i] = lct.make_vertex(i);
189 for (int i = 0; i + 1 < N; ++i)
190 lct.link(nd[i], nd[i + 1]);
191
192 // reroot at node 3
193 lct.make_root(nd[3]);
194 EXPECT_EQ(lct.find_root(nd[0]), nd[3]);
195 EXPECT_EQ(lct.find_root(nd[4]), nd[3]);
196}
197
199{
200 constexpr int N = 7;
201 std::vector<Link_Cut_Tree::Node *> nd(N);
202 for (int i = 0; i < N; ++i)
203 nd[i] = lct.make_vertex(i);
204 for (int i = 0; i + 1 < N; ++i)
205 lct.link(nd[i], nd[i + 1]);
206
207 for (int r = 0; r < N; ++r)
208 {
209 lct.make_root(nd[r]);
210 EXPECT_EQ(lct.find_root(nd[0]), nd[r]);
211 for (int i = 0; i < N; ++i)
212 EXPECT_TRUE(lct.connected(nd[i], nd[r]));
213 }
214}
215
217{
218 constexpr int N = 8;
219 std::vector<Link_Cut_Tree::Node *> nd(N);
220 for (int i = 0; i < N; ++i)
221 nd[i] = lct.make_vertex(i);
222 for (int i = 0; i + 1 < N; ++i)
223 lct.link(nd[i], nd[i + 1]);
224
225 for (int r = N - 1; r >= 0; --r)
226 {
227 lct.make_root(nd[r]);
228 for (int i = 0; i < N; ++i)
229 EXPECT_EQ(lct.find_root(nd[i]), nd[r]);
230 }
231}
232
233// ===================================================================
234// C. LCA
235// ===================================================================
236
238{
239 auto * x = lct.make_vertex(1);
240 EXPECT_EQ(lct.lca(x, x), x);
241}
242
244{
245 // path 0-1-2-3-4, root at 0
246 constexpr int N = 5;
247 std::vector<Link_Cut_Tree::Node *> nd(N);
248 for (int i = 0; i < N; ++i)
249 nd[i] = lct.make_vertex(i);
250 for (int i = 0; i + 1 < N; ++i)
251 lct.link(nd[i], nd[i + 1]);
252
253 lct.make_root(nd[0]);
254 // on a path rooted at 0, lca(i, j) = min(i, j)
255 for (int i = 0; i < N; ++i)
256 for (int j = i; j < N; ++j)
257 EXPECT_EQ(lct.lca(nd[i], nd[j]), nd[i]);
258}
259
261{
262 // 0
263 // / \ .
264 // 1 2
265 // / \ .
266 // 3 4
267 auto * n0 = lct.make_vertex(0);
268 auto * n1 = lct.make_vertex(1);
269 auto * n2 = lct.make_vertex(2);
270 auto * n3 = lct.make_vertex(3);
271 auto * n4 = lct.make_vertex(4);
272
273 lct.make_root(n0);
274 lct.link(n1, n0);
275 lct.link(n2, n0);
276 lct.link(n3, n1);
277 lct.link(n4, n1);
278
279 EXPECT_EQ(lct.lca(n3, n4), n1);
280 EXPECT_EQ(lct.lca(n3, n2), n0);
281 EXPECT_EQ(lct.lca(n1, n2), n0);
282 EXPECT_EQ(lct.lca(n0, n4), n0);
283}
284
285// ===================================================================
286// D. Error handling
287// ===================================================================
288
290{
291 auto * u = lct.make_vertex(1);
292 auto * v = lct.make_vertex(2);
293 lct.link(u, v);
294 EXPECT_THROW(lct.link(u, v), std::domain_error);
295}
296
298{
299 auto * x = lct.make_vertex(1);
300 EXPECT_THROW(lct.link(x, x), std::invalid_argument);
301}
302
304{
305 auto * u = lct.make_vertex(1);
306 auto * v = lct.make_vertex(2);
307 auto * w = lct.make_vertex(3);
308
309 // not connected at all
310 EXPECT_THROW(lct.cut(u, v), std::domain_error);
311
312 // connected but no direct edge: u-v-w, try to cut u-w
313 lct.link(u, v);
314 lct.link(v, w);
315 EXPECT_THROW(lct.cut(u, w), std::domain_error);
316}
317
319{
320 EXPECT_THROW(lct.make_root(nullptr), std::invalid_argument);
321 EXPECT_THROW(lct.find_root(nullptr), std::invalid_argument);
322 EXPECT_THROW(lct.connected(nullptr, nullptr), std::invalid_argument);
323 auto * x = lct.make_vertex(1);
324 EXPECT_THROW(lct.link(nullptr, x), std::invalid_argument);
325 EXPECT_THROW(lct.cut(nullptr, x), std::invalid_argument);
326 EXPECT_THROW(lct.lca(nullptr, x), std::invalid_argument);
327}
328
330{
331 auto * u = lct.make_vertex(1);
332 auto * v = lct.make_vertex(2);
333 EXPECT_THROW(lct.lca(u, v), std::domain_error);
334}
335
337{
338 auto * u = lct.make_vertex(1);
339 auto * v = lct.make_vertex(2);
340
341 EXPECT_THROW(lct.path_query(u, v), std::domain_error);
342 EXPECT_THROW(lct.path_size(u, v), std::domain_error);
343
344 bool called = false;
345 EXPECT_THROW(lct.for_each_on_path(u, v, [&](auto *) { called = true; }),
346 std::domain_error);
347 EXPECT_FALSE(called);
348}
349
350// ===================================================================
351// D2. num_components, tree_size, depth, parent
352// ===================================================================
353
355{
356 EXPECT_EQ(lct.num_components(), 0u);
357
358 auto * a = lct.make_vertex(1);
359 auto * b = lct.make_vertex(2);
360 auto * c = lct.make_vertex(3);
361 EXPECT_EQ(lct.num_components(), 3u);
362
363 lct.link(a, b);
364 EXPECT_EQ(lct.num_components(), 2u);
365
366 lct.link(b, c);
367 EXPECT_EQ(lct.num_components(), 1u);
368
369 lct.cut(a, b);
370 EXPECT_EQ(lct.num_components(), 2u);
371}
372
374{
375 auto * a = lct.make_vertex(1);
376 auto * b = lct.make_vertex(2);
377 auto * c = lct.make_vertex(3);
378
379 EXPECT_EQ(lct.tree_size(a), 1u);
380
381 lct.link(a, b);
382 EXPECT_EQ(lct.tree_size(a), 2u);
383 EXPECT_EQ(lct.tree_size(b), 2u);
384
385 lct.link(b, c);
386 EXPECT_EQ(lct.tree_size(a), 3u);
387
388 lct.cut(a, b);
389 EXPECT_EQ(lct.tree_size(a), 1u);
390 EXPECT_EQ(lct.tree_size(b), 2u);
391}
392
394{
395 // path 0-1-2-3-4, root at 0
396 constexpr int N = 5;
397 std::vector<Link_Cut_Tree::Node *> nd(N);
398 for (int i = 0; i < N; ++i)
399 nd[i] = lct.make_vertex(i);
400 for (int i = 0; i + 1 < N; ++i)
401 lct.link(nd[i], nd[i + 1]);
402
403 lct.make_root(nd[0]);
404 for (int i = 0; i < N; ++i)
405 EXPECT_EQ(lct.depth(nd[i]), static_cast<size_t>(i));
406
407 // reroot at nd[2]: depths become |i - 2|
408 lct.make_root(nd[2]);
409 for (int i = 0; i < N; ++i)
410 EXPECT_EQ(lct.depth(nd[i]), static_cast<size_t>(std::abs(i - 2)));
411}
412
414{
415 // path 0-1-2-3, root at 0
416 constexpr int N = 4;
417 std::vector<Link_Cut_Tree::Node *> nd(N);
418 for (int i = 0; i < N; ++i)
419 nd[i] = lct.make_vertex(i);
420 for (int i = 0; i + 1 < N; ++i)
421 lct.link(nd[i], nd[i + 1]);
422
423 lct.make_root(nd[0]);
424 EXPECT_EQ(lct.parent(nd[0]), nullptr);
425 EXPECT_EQ(lct.parent(nd[1]), nd[0]);
426 EXPECT_EQ(lct.parent(nd[2]), nd[1]);
427 EXPECT_EQ(lct.parent(nd[3]), nd[2]);
428
429 // reroot at nd[3]
430 lct.make_root(nd[3]);
431 EXPECT_EQ(lct.parent(nd[3]), nullptr);
432 EXPECT_EQ(lct.parent(nd[2]), nd[3]);
433 EXPECT_EQ(lct.parent(nd[0]), nd[1]);
434}
435
437{
438 // 0
439 // / | \ .
440 // 1 2 3
441 auto * center = lct.make_vertex(0);
442 auto * l1 = lct.make_vertex(1);
443 auto * l2 = lct.make_vertex(2);
444 auto * l3 = lct.make_vertex(3);
445
446 lct.make_root(center);
447 lct.link(l1, center);
448 lct.link(l2, center);
449 lct.link(l3, center);
450
451 EXPECT_EQ(lct.parent(center), nullptr);
452 EXPECT_EQ(lct.parent(l1), center);
453 EXPECT_EQ(lct.parent(l2), center);
454 EXPECT_EQ(lct.parent(l3), center);
455}
456
457// ===================================================================
458// D3. for_each_on_path, for_each_node
459// ===================================================================
460
462{
463 constexpr int N = 5;
464 std::vector<Link_Cut_Tree::Node *> nd(N);
465 for (int i = 0; i < N; ++i)
466 nd[i] = lct.make_vertex(i);
467 for (int i = 0; i + 1 < N; ++i)
468 lct.link(nd[i], nd[i + 1]);
469
470 // collect values on path from nd[1] to nd[3]
471 std::vector<int> collected;
472 lct.for_each_on_path(nd[1], nd[3],
473 [&](Link_Cut_Tree::Node * n) { collected.push_back(lct.get_val(n)); });
474
475 ASSERT_EQ(collected.size(), 3u);
476 EXPECT_EQ(collected[0], 1);
477 EXPECT_EQ(collected[1], 2);
478 EXPECT_EQ(collected[2], 3);
479}
480
482{
483 lct.make_vertex(10);
484 lct.make_vertex(20);
485 lct.make_vertex(30);
486
487 int sum = 0;
488 lct.for_each_node([&](Link_Cut_Tree::Node * n) { sum += lct.get_val(n); });
489 EXPECT_EQ(sum, 60);
490}
491
492// ===================================================================
493// D4. Batch construction: make_path, make_vertices, link_edges
494// ===================================================================
495
497{
498 auto path = lct.make_path({10, 20, 30, 40});
499 EXPECT_EQ(lct.size(), 4u);
500 EXPECT_EQ(lct.num_components(), 1u);
501 EXPECT_TRUE(lct.connected(path(0), path(3)));
502 EXPECT_EQ(lct.path_size(path(0), path(3)), 4u);
503 EXPECT_EQ(lct.get_val(path(0)), 10);
504 EXPECT_EQ(lct.get_val(path(3)), 40);
505}
506
508{
509 auto verts = lct.make_vertices({1, 2, 3});
510 EXPECT_EQ(lct.size(), 3u);
511 EXPECT_EQ(lct.num_components(), 3u);
512 EXPECT_FALSE(lct.connected(verts(0), verts(1)));
513}
514
516{
517 auto verts = lct.make_vertices({1, 2, 3, 4});
518
519 std::vector<std::pair<Link_Cut_Tree::Node *, Link_Cut_Tree::Node *>> edges = {
520 {verts(0), verts(1)},
521 {verts(1), verts(2)},
522 {verts(2), verts(3)}
523 };
524 lct.link_edges(edges);
525
526 EXPECT_EQ(lct.num_components(), 1u);
527 EXPECT_TRUE(lct.connected(verts(0), verts(3)));
528}
529
530// ===================================================================
531// E. Path aggregates — SumMonoid
532// ===================================================================
533
539
541{
542 auto * x = lct.make_vertex(7);
543 EXPECT_EQ(lct.path_query(x, x), 7);
544}
545
547{
548 // path: 1 - 2 - 3 - 4 - 5
549 constexpr int N = 5;
551 std::vector<NodePtr> nd(N);
552 for (int i = 0; i < N; ++i)
553 nd[i] = lct.make_vertex(i + 1);
554 for (int i = 0; i + 1 < N; ++i)
555 lct.link(nd[i], nd[i + 1]);
556
557 // sum of path from nd[0] to nd[4] = 1+2+3+4+5 = 15
558 EXPECT_EQ(lct.path_query(nd[0], nd[4]), 15);
559
560 // sub-paths
561 EXPECT_EQ(lct.path_query(nd[1], nd[3]), 2 + 3 + 4);
562 EXPECT_EQ(lct.path_query(nd[0], nd[0]), 1);
563}
564
566{
567 auto * u = lct.make_vertex(10);
568 auto * v = lct.make_vertex(20);
569 lct.link(u, v);
570
571 EXPECT_EQ(lct.path_query(u, v), 30);
572
573 lct.set_val(u, 100);
574 EXPECT_EQ(lct.path_query(u, v), 120);
575}
576
578{
579 auto * a = lct.make_vertex(1);
580 auto * b = lct.make_vertex(2);
581 auto * c = lct.make_vertex(3);
582
583 lct.link(a, b);
584 lct.link(b, c);
585 EXPECT_EQ(lct.path_query(a, c), 6);
586
587 lct.cut(a, b);
588 EXPECT_EQ(lct.path_query(b, c), 5);
589
590 lct.link(a, c);
591 EXPECT_EQ(lct.path_query(a, b), 6);
592}
593
594// ===================================================================
595// E2. Path aggregates — MinMonoid
596// ===================================================================
597
603
605{
607 constexpr int N = 5;
608 std::vector<NodePtr> nd(N);
609 int vals[] = {7, 2, 9, 1, 5};
610 for (int i = 0; i < N; ++i)
611 nd[i] = lct.make_vertex(vals[i]);
612 for (int i = 0; i + 1 < N; ++i)
613 lct.link(nd[i], nd[i + 1]);
614
615 EXPECT_EQ(lct.path_query(nd[0], nd[4]), 1);
616 EXPECT_EQ(lct.path_query(nd[0], nd[2]), 2);
617 EXPECT_EQ(lct.path_query(nd[2], nd[4]), 1);
618}
619
620// ===================================================================
621// E3. Path aggregates — MaxMonoid
622// ===================================================================
623
629
631{
633 constexpr int N = 5;
634 std::vector<NodePtr> nd(N);
635 int vals[] = {3, 8, 1, 6, 4};
636 for (int i = 0; i < N; ++i)
637 nd[i] = lct.make_vertex(vals[i]);
638 for (int i = 0; i + 1 < N; ++i)
639 lct.link(nd[i], nd[i + 1]);
640
641 EXPECT_EQ(lct.path_query(nd[0], nd[4]), 8);
642 EXPECT_EQ(lct.path_query(nd[2], nd[4]), 6);
643}
644
645// ===================================================================
646// E4. Path aggregates — XorMonoid
647// ===================================================================
648
654
656{
657 auto * a = lct.make_vertex(5); // 101
658 auto * b = lct.make_vertex(3); // 011
659 auto * c = lct.make_vertex(6); // 110
660
661 lct.link(a, b);
662 lct.link(b, c);
663
664 EXPECT_EQ(lct.path_query(a, c), 5 ^ 3 ^ 6);
665 EXPECT_EQ(lct.path_query(a, b), 5 ^ 3);
666}
667
668// ===================================================================
669// E5. Path aggregates — GcdMonoid
670// ===================================================================
671
677
679{
680 auto * a = lct.make_vertex(12);
681 auto * b = lct.make_vertex(18);
682 auto * c = lct.make_vertex(24);
683
684 lct.link(a, b);
685 lct.link(b, c);
686
687 EXPECT_EQ(lct.path_query(a, c), 6); // gcd(12, 18, 24) = 6
688 EXPECT_EQ(lct.path_query(a, b), 6); // gcd(12, 18) = 6
689 EXPECT_EQ(lct.path_query(b, c), 6); // gcd(18, 24) = 6
690
691 lct.set_val(b, 15);
692 EXPECT_EQ(lct.path_query(a, c), 3); // gcd(12, 15, 24) = 3
693}
694
695// ===================================================================
696// E6. Path aggregates — ProductMonoid
697// ===================================================================
698
704
706{
707 auto * a = lct.make_vertex(2LL);
708 auto * b = lct.make_vertex(3LL);
709 auto * c = lct.make_vertex(5LL);
710
711 lct.link(a, b);
712 lct.link(b, c);
713
714 EXPECT_EQ(lct.path_query(a, c), 30LL); // 2*3*5
715 EXPECT_EQ(lct.path_query(a, b), 6LL); // 2*3
716}
717
718// ===================================================================
719// F. Lazy path updates — AddLazyTag + SumMonoid
720// ===================================================================
721
728
730{
733 using NodePtr = LCT::Node *;
734
735 constexpr int N = 5;
736 std::vector<NodePtr> nd(N);
737 for (int i = 0; i < N; ++i)
738 nd[i] = lct.make_vertex(0LL);
739 for (int i = 0; i + 1 < N; ++i)
740 lct.link(nd[i], nd[i + 1]);
741
742 // add 10 to every node on path 0..4 (5 nodes, sum = 50)
743 lct.path_apply(nd[0], nd[4], 10LL);
744 EXPECT_EQ(lct.path_query(nd[0], nd[4]), 50LL);
745
746 // add 5 to sub-path 1..3 (3 nodes)
747 lct.path_apply(nd[1], nd[3], 5LL);
748 // nd[0]=10, nd[1]=15, nd[2]=15, nd[3]=15, nd[4]=10 => total = 65
749 EXPECT_EQ(lct.path_query(nd[0], nd[4]), 65LL);
750
751 // query sub-path 1..3 => 15+15+15 = 45
752 EXPECT_EQ(lct.path_query(nd[1], nd[3]), 45LL);
753}
754
756{
757 auto * u = lct.make_vertex(1LL);
758 auto * v = lct.make_vertex(2LL);
759 EXPECT_THROW(lct.path_apply(u, v, 5LL), std::domain_error);
760}
761
762// ===================================================================
763// F2. Lazy path updates — AssignLazyTag + SumMonoid
764// ===================================================================
765
772
774{
777 using NodePtr = LCT::Node *;
778
779 constexpr int N = 5;
780 std::vector<NodePtr> nd(N);
781 for (int i = 0; i < N; ++i)
782 nd[i] = lct.make_vertex(static_cast<long long>(i + 1));
783 for (int i = 0; i + 1 < N; ++i)
784 lct.link(nd[i], nd[i + 1]);
785
786 // initial sum = 1+2+3+4+5 = 15
787 EXPECT_EQ(lct.path_query(nd[0], nd[4]), 15LL);
788
789 // assign 10 to all 5 nodes → sum = 50
790 typename AssignLazyTag<long long>::tag_type assign_10 = {10LL, true};
791 lct.path_apply(nd[0], nd[4], assign_10);
792 EXPECT_EQ(lct.path_query(nd[0], nd[4]), 50LL);
793
794 // assign 3 to sub-path 1..3 (3 nodes) → nd[0]=10, 1..3=3, nd[4]=10
795 // sum = 10 + 3 + 3 + 3 + 10 = 29
796 typename AssignLazyTag<long long>::tag_type assign_3 = {3LL, true};
797 lct.path_apply(nd[1], nd[3], assign_3);
798 EXPECT_EQ(lct.path_query(nd[0], nd[4]), 29LL);
799 EXPECT_EQ(lct.path_query(nd[1], nd[3]), 9LL);
800}
801
802// ===================================================================
803// G. Randomised stress test vs naive oracle
804// ===================================================================
805
806namespace
807{
808
809// Simple naive forest using parent array + DFS for connected queries
810struct NaiveForest
811{
812 int n;
813 std::vector<std::vector<int>> adj;
814
815 explicit NaiveForest(int n) : n(n), adj(n) {}
816
817 void link(int u, int v)
818 {
819 adj[u].push_back(v);
820 adj[v].push_back(u);
821 }
822
823 void cut(int u, int v)
824 {
825 adj[u].erase(std::find(adj[u].begin(), adj[u].end(), v));
826 adj[v].erase(std::find(adj[v].begin(), adj[v].end(), u));
827 }
828
829 bool connected(int u, int v) const
830 {
831 if (u == v)
832 return true;
833 std::vector<bool> visited(n, false);
834 std::vector<int> stk = {u};
835 visited[u] = true;
836 while (not stk.empty())
837 {
838 int cur = stk.back();
839 stk.pop_back();
840 for (int nb : adj[cur])
841 if (not visited[nb])
842 {
843 if (nb == v)
844 return true;
845 visited[nb] = true;
846 stk.push_back(nb);
847 }
848 }
849 return false;
850 }
851
852 bool has_edge(int u, int v) const
853 {
854 return std::find(adj[u].begin(), adj[u].end(), v) != adj[u].end();
855 }
856};
857
858} // anonymous namespace
859
861{
862 constexpr int N = 200;
863 constexpr int OPS = 2000;
864
865 std::mt19937 rng(12345);
866
867 Link_Cut_Tree lct;
868 std::vector<Link_Cut_Tree::Node *> nd(N);
869 for (int i = 0; i < N; ++i)
870 nd[i] = lct.make_vertex(i);
871
872 NaiveForest oracle(N);
873
874 // track edges for cut
875 std::vector<std::pair<int, int>> edges;
876
877 for (int op = 0; op < OPS; ++op)
878 {
879 int choice = std::uniform_int_distribution<int>(0, 2)(rng);
880
881 if (choice == 0 and edges.size() < static_cast<size_t>(N - 1))
882 {
883 // try to link two random disconnected nodes
884 int u = std::uniform_int_distribution<int>(0, N - 1)(rng);
885 int v = std::uniform_int_distribution<int>(0, N - 1)(rng);
886 if (u != v and not oracle.connected(u, v))
887 {
888 lct.link(nd[u], nd[v]);
889 oracle.link(u, v);
890 edges.push_back({u, v});
891 }
892 }
893 else if (choice == 1 and not edges.empty())
894 {
895 // cut a random existing edge
896 size_t idx = std::uniform_int_distribution<size_t>(
897 0, edges.size() - 1)(rng);
898 auto [u, v] = edges[idx];
899 edges[idx] = edges.back();
900 edges.pop_back();
901
902 lct.cut(nd[u], nd[v]);
903 oracle.cut(u, v);
904 }
905 else
906 {
907 // query connected
908 int u = std::uniform_int_distribution<int>(0, N - 1)(rng);
909 int v = std::uniform_int_distribution<int>(0, N - 1)(rng);
910 EXPECT_EQ(lct.connected(nd[u], nd[v]),
911 oracle.connected(u, v))
912 << "mismatch at op=" << op << " u=" << u << " v=" << v;
913 }
914 }
915}
916
917// ===================================================================
918// G2. Randomised path-query stress (SumMonoid)
919// ===================================================================
920
921namespace
922{
923
924struct NaiveSumForest
925{
926 int n;
927 std::vector<int> val;
928 std::vector<std::vector<int>> adj;
929
930 explicit NaiveSumForest(int n) : n(n), val(n, 0), adj(n) {}
931
932 void link(int u, int v) { adj[u].push_back(v); adj[v].push_back(u); }
933 void cut(int u, int v)
934 {
935 adj[u].erase(std::find(adj[u].begin(), adj[u].end(), v));
936 adj[v].erase(std::find(adj[v].begin(), adj[v].end(), u));
937 }
938
939 bool connected(int u, int v) const
940 {
941 if (u == v) return true;
942 std::vector<bool> vis(n, false);
943 std::vector<int> stk = {u};
944 vis[u] = true;
945 while (not stk.empty())
946 {
947 int c = stk.back(); stk.pop_back();
948 for (int nb : adj[c])
949 if (not vis[nb])
950 { if (nb == v) return true; vis[nb] = true; stk.push_back(nb); }
951 }
952 return false;
953 }
954
955 int path_sum(int u, int v) const
956 {
957 // BFS to find path, then sum
958 std::vector<int> par(n, -1);
959 std::vector<bool> vis(n, false);
960 std::vector<int> q = {u};
961 vis[u] = true;
962 while (not q.empty())
963 {
964 int c = q.back(); q.pop_back();
965 if (c == v) break;
966 for (int nb : adj[c])
967 if (not vis[nb])
968 { vis[nb] = true; par[nb] = c; q.push_back(nb); }
969 }
970 int s = 0;
971 for (int c = v; c != -1; c = par[c])
972 s += val[c];
973 return s;
974 }
975};
976
977} // anonymous namespace
978
980{
981 constexpr int N = 100;
982 constexpr int OPS = 1000;
983
984 std::mt19937 rng(54321);
985
988 std::vector<NodePtr> nd(N);
989
990 NaiveSumForest oracle(N);
991
992 for (int i = 0; i < N; ++i)
993 {
994 int v = std::uniform_int_distribution<int>(1, 100)(rng);
995 nd[i] = lct.make_vertex(v);
996 oracle.val[i] = v;
997 }
998
999 // build a random tree on N nodes (random Prüfer-like sequence)
1000 std::vector<std::pair<int, int>> edges;
1001 std::vector<int> perm(N);
1002 std::iota(perm.begin(), perm.end(), 0);
1003 std::shuffle(perm.begin(), perm.end(), rng);
1004 for (int i = 1; i < N; ++i)
1005 {
1006 int par = perm[std::uniform_int_distribution<int>(0, i - 1)(rng)];
1007 int cur = perm[i];
1008 lct.link(nd[cur], nd[par]);
1009 oracle.link(cur, par);
1010 edges.push_back({cur, par});
1011 }
1012
1013 for (int op = 0; op < OPS; ++op)
1014 {
1015 int choice = std::uniform_int_distribution<int>(0, 3)(rng);
1016
1017 if (choice == 0)
1018 {
1019 // query path sum between two connected nodes
1020 int u = std::uniform_int_distribution<int>(0, N - 1)(rng);
1021 int v = std::uniform_int_distribution<int>(0, N - 1)(rng);
1022 if (oracle.connected(u, v))
1023 {
1024 int expected = oracle.path_sum(u, v);
1025 int got = lct.path_query(nd[u], nd[v]);
1027 << "path_sum mismatch at op=" << op
1028 << " u=" << u << " v=" << v;
1029 }
1030 }
1031 else if (choice == 1)
1032 {
1033 // update a value
1034 int idx = std::uniform_int_distribution<int>(0, N - 1)(rng);
1035 int nv = std::uniform_int_distribution<int>(1, 100)(rng);
1036 lct.set_val(nd[idx], nv);
1037 oracle.val[idx] = nv;
1038 }
1039 else if (choice == 2 and not edges.empty())
1040 {
1041 // cut a random edge
1042 size_t ei = std::uniform_int_distribution<size_t>(
1043 0, edges.size() - 1)(rng);
1044 auto [u, v] = edges[ei];
1045 edges[ei] = edges.back();
1046 edges.pop_back();
1047 lct.cut(nd[u], nd[v]);
1048 oracle.cut(u, v);
1049 }
1050 else if (choice == 3 and edges.size() < static_cast<size_t>(N - 1))
1051 {
1052 // try to link two disconnected nodes
1053 int u = std::uniform_int_distribution<int>(0, N - 1)(rng);
1054 int v = std::uniform_int_distribution<int>(0, N - 1)(rng);
1055 if (u != v and not oracle.connected(u, v))
1056 {
1057 lct.link(nd[u], nd[v]);
1058 oracle.link(u, v);
1059 edges.push_back({u, v});
1060 }
1061 }
1062 }
1063}
1064
1065// ===================================================================
1066// H. Performance sanity
1067// ===================================================================
1068
1070{
1071 constexpr int N = 50000;
1072 Link_Cut_Tree lct;
1073 std::vector<Link_Cut_Tree::Node *> nd(N);
1074 for (int i = 0; i < N; ++i)
1075 nd[i] = lct.make_vertex(i);
1076
1077 // build a long path
1078 for (int i = 0; i + 1 < N; ++i)
1079 lct.link(nd[i], nd[i + 1]);
1080
1081 // various queries should not blow up
1082 EXPECT_TRUE(lct.connected(nd[0], nd[N - 1]));
1083 EXPECT_EQ(lct.path_size(nd[0], nd[N - 1]), static_cast<size_t>(N));
1084
1085 // reroot and query again
1086 lct.make_root(nd[N / 2]);
1087 EXPECT_EQ(lct.find_root(nd[0]), nd[N / 2]);
1088
1089 // cut and re-link near the middle
1090 lct.cut(nd[N / 2], nd[N / 2 + 1]);
1091 EXPECT_FALSE(lct.connected(nd[0], nd[N - 1]));
1092
1093 lct.link(nd[N / 2], nd[N / 2 + 1]);
1094 EXPECT_TRUE(lct.connected(nd[0], nd[N - 1]));
1095
1096 // Functional smoke-check: repeated queries must return consistent results.
1097 for (int i = 0; i < 512; ++i)
1098 {
1099 EXPECT_TRUE(lct.connected(nd[0], nd[N - 1]));
1100 EXPECT_EQ(lct.find_root(nd[0]), lct.find_root(nd[N - 1]));
1101 EXPECT_EQ(lct.path_size(nd[0], nd[N - 1]), static_cast<size_t>(N));
1102 }
1103}
1104
1105// ===================================================================
1106// I. Edge-as-Node Link-Cut Tree
1107// ===================================================================
1108
1114
1116{
1117 auto * u = lct.make_vertex(0);
1118 auto * v = lct.make_vertex(1);
1119
1120 lct.link(u, v, 10); // edge weight = 10
1121 EXPECT_TRUE(lct.connected(u, v));
1122 EXPECT_EQ(lct.size(), 2u); // only 2 vertices, not the edge node
1123}
1124
1126{
1127 auto * u = lct.make_vertex(10);
1128 auto * v = lct.make_vertex(20);
1129
1130 EXPECT_EQ(lct.get_vertex_val(u), 10);
1131 EXPECT_EQ(lct.get_vertex_val(v), 20);
1132
1133 lct.set_vertex_val(v, 25);
1134 EXPECT_EQ(lct.get_vertex_val(v), 25);
1135
1136 lct.link(u, v, 7);
1137 EXPECT_EQ(lct.path_query(u, v), 7);
1138 EXPECT_EQ(lct.get_vertex_val(u), 10);
1139 EXPECT_EQ(lct.get_vertex_val(v), 25);
1140}
1141
1143{
1144 // Build: u --(5)-- v --(7)-- w
1145 auto * u = lct.make_vertex(0);
1146 auto * v = lct.make_vertex(1);
1147 auto * w = lct.make_vertex(2);
1148
1149 lct.link(u, v, 5);
1150 lct.link(v, w, 7);
1151
1152 // Max edge weight on path u-w = max(5, 7) = 7
1153 EXPECT_EQ(lct.path_query(u, w), 7);
1154 EXPECT_EQ(lct.path_query(u, v), 5);
1155 EXPECT_EQ(lct.path_query(v, w), 7);
1156}
1157
1159{
1160 auto * u = lct.make_vertex(0);
1161 auto * v = lct.make_vertex(1);
1162
1163 lct.link(u, v, 10);
1164
1165 // Get the edge node (it's the only edge)
1166 // After link, the structure is: u ← edge_node → v
1167 // We need to access the edge through the internal structure
1168 // For now, test that path_query works
1169 EXPECT_EQ(lct.path_query(u, v), 10);
1170}
1171
1173{
1174 auto * u = lct.make_vertex(0);
1175 auto * v = lct.make_vertex(1);
1176
1177 lct.link(u, v, 100);
1178 EXPECT_TRUE(lct.connected(u, v));
1179
1180 lct.cut(u, v);
1181 EXPECT_FALSE(lct.connected(u, v));
1182}
1183
1185{
1186 // Simple MST: 3 vertices, try edges with weights
1187 // 1
1188 // / \
1189 // 0 2
1190
1191 auto * v0 = lct.make_vertex(0);
1192 auto * v1 = lct.make_vertex(1);
1193 auto * v2 = lct.make_vertex(2);
1194
1195 // Add edges: (0,1) weight 2, (1,2) weight 3, (0,2) weight 5
1196 lct.link(v0, v1, 2);
1197 lct.link(v1, v2, 3);
1198
1199 // If we add (0,2) with weight 5, it creates a cycle
1200 // The max weight on path 0-2 is max(2, 3) = 3
1201 // So we could remove (1,2) if we add (0,2)
1202 EXPECT_EQ(lct.path_query(v0, v2), 3); // max of {2, 3}
1203}
1204
1206{
1207 // a
1208 // /|\
1209 // b c d
1210
1211 auto * a = lct.make_vertex(100);
1212 auto * b = lct.make_vertex(101);
1213 auto * c = lct.make_vertex(102);
1214 auto * d = lct.make_vertex(103);
1215
1216 lct.link(b, a, 10);
1217 lct.link(c, a, 20);
1218 lct.link(d, a, 30);
1219
1220 EXPECT_EQ(lct.num_components(), 1u);
1221 EXPECT_EQ(lct.size(), 4u);
1222
1223 // Paths from b to other nodes
1224 EXPECT_EQ(lct.path_query(b, c), 20); // max(10, 20)
1225 EXPECT_EQ(lct.path_query(b, d), 30); // max(10, 30)
1226}
1227
1228// ===================================================================
1229// J. Edge-as-Node: edge value update and stress test
1230// ===================================================================
1231
1233{
1234 auto * u = lct.make_vertex(0);
1235 auto * v = lct.make_vertex(1);
1236 auto * w = lct.make_vertex(2);
1237
1238 lct.link(u, v, 5);
1239 lct.link(v, w, 3);
1240
1241 EXPECT_EQ(lct.path_query(u, w), 5); // max(5, 3) = 5
1242
1243 lct.set_edge_val(u, v, 1);
1244 EXPECT_EQ(lct.path_query(u, w), 3); // max(1, 3) = 3
1245
1246 EXPECT_EQ(lct.get_edge_val(u, v), 1);
1247 EXPECT_EQ(lct.get_edge_val(v, w), 3);
1248}
1249
1251{
1252 auto * a = lct.make_vertex(0);
1253 auto * b = lct.make_vertex(1);
1254 auto * c = lct.make_vertex(2);
1255
1256 lct.link(a, b, 10);
1257 lct.link(b, c, 20);
1258 EXPECT_EQ(lct.path_query(a, c), 20);
1259
1260 lct.cut(a, b);
1261 EXPECT_FALSE(lct.connected(a, b));
1262 EXPECT_TRUE(lct.connected(b, c));
1263
1264 lct.link(a, c, 5);
1265 EXPECT_EQ(lct.path_query(a, b), 20); // a-c(5)-b... wait: a--5--c--20--b => max(5, 20) = 20
1266}
1267
1269{
1270 auto * u = lct.make_vertex(0);
1271 auto * v = lct.make_vertex(1);
1272
1273 // self-loop
1274 EXPECT_THROW(lct.link(u, u, 1), std::invalid_argument);
1275
1276 // null handle
1277 EXPECT_THROW(lct.link(nullptr, v, 1), std::invalid_argument);
1278
1279 // link then double-link
1280 lct.link(u, v, 5);
1281 EXPECT_THROW(lct.link(u, v, 10), std::domain_error);
1282
1283 // cut non-existent edge
1284 auto * w = lct.make_vertex(2);
1285 EXPECT_THROW(lct.cut(u, w), std::domain_error);
1286}
1287
1288// ===================================================================
1289// K. Edge-as-Node: randomised stress vs naive oracle
1290// ===================================================================
1291
1292namespace
1293{
1294
1295struct NaiveEdgeForest
1296{
1297 int n;
1298 struct Edge { int u, v, w; };
1299 std::vector<Edge> edges;
1300 std::vector<std::vector<std::pair<int, int>>> adj; // adj[u] = {(v, edge_idx)}
1301
1302 explicit NaiveEdgeForest(int n) : n(n), adj(n) {}
1303
1304 void link(int u, int v, int w)
1305 {
1306 int idx = static_cast<int>(edges.size());
1307 edges.push_back({u, v, w});
1308 adj[u].push_back({v, idx});
1309 adj[v].push_back({u, idx});
1310 }
1311
1312 void cut(int u, int v)
1313 {
1314 for (auto it = adj[u].begin(); it != adj[u].end(); ++it)
1315 if (it->first == v) { adj[u].erase(it); break; }
1316 for (auto it = adj[v].begin(); it != adj[v].end(); ++it)
1317 if (it->first == u) { adj[v].erase(it); break; }
1318 }
1319
1320 bool connected(int u, int v) const
1321 {
1322 if (u == v) return true;
1323 std::vector<bool> vis(n, false);
1324 std::vector<int> stk = {u};
1325 vis[u] = true;
1326 while (not stk.empty())
1327 {
1328 int c = stk.back(); stk.pop_back();
1329 for (auto [nb, _] : adj[c])
1330 if (not vis[nb])
1331 { if (nb == v) return true; vis[nb] = true; stk.push_back(nb); }
1332 }
1333 return false;
1334 }
1335
1336 bool has_edge(int u, int v) const
1337 {
1338 for (auto [nb, _] : adj[u])
1339 if (nb == v) return true;
1340 return false;
1341 }
1342
1343 int path_max(int u, int v) const
1344 {
1345 std::vector<int> par(n, -1);
1346 std::vector<int> par_edge(n, -1);
1347 std::vector<bool> vis(n, false);
1348 std::vector<int> q = {u};
1349 vis[u] = true;
1350 while (not q.empty())
1351 {
1352 int c = q.back(); q.pop_back();
1353 if (c == v) break;
1354 for (auto [nb, eidx] : adj[c])
1355 if (not vis[nb])
1356 { vis[nb] = true; par[nb] = c; par_edge[nb] = eidx; q.push_back(nb); }
1357 }
1358 int mx = std::numeric_limits<int>::lowest();
1359 for (int c = v; par[c] != -1; c = par[c])
1360 mx = std::max(mx, edges[par_edge[c]].w);
1361 return mx;
1362 }
1363};
1364
1365} // anonymous namespace
1366
1368{
1369 constexpr int N = 100;
1370 constexpr int OPS = 1500;
1371
1372 std::mt19937 rng(99887);
1373
1376 std::vector<NodePtr> nd(N);
1377 for (int i = 0; i < N; ++i)
1378 nd[i] = lct.make_vertex(i);
1379
1380 NaiveEdgeForest oracle(N);
1381 std::vector<std::pair<int, int>> user_edges;
1382
1383 for (int op = 0; op < OPS; ++op)
1384 {
1385 int choice = std::uniform_int_distribution<int>(0, 2)(rng);
1386
1387 if (choice == 0 and user_edges.size() < static_cast<size_t>(N - 1))
1388 {
1389 int u = std::uniform_int_distribution<int>(0, N - 1)(rng);
1390 int v = std::uniform_int_distribution<int>(0, N - 1)(rng);
1391 if (u != v and not oracle.connected(u, v))
1392 {
1393 int w = std::uniform_int_distribution<int>(1, 1000)(rng);
1394 lct.link(nd[u], nd[v], w);
1395 oracle.link(u, v, w);
1396 user_edges.push_back({u, v});
1397 }
1398 }
1399 else if (choice == 1 and not user_edges.empty())
1400 {
1401 size_t idx = std::uniform_int_distribution<size_t>(
1402 0, user_edges.size() - 1)(rng);
1403 auto [u, v] = user_edges[idx];
1404 user_edges[idx] = user_edges.back();
1405 user_edges.pop_back();
1406
1407 lct.cut(nd[u], nd[v]);
1408 oracle.cut(u, v);
1409 }
1410 else
1411 {
1412 int u = std::uniform_int_distribution<int>(0, N - 1)(rng);
1413 int v = std::uniform_int_distribution<int>(0, N - 1)(rng);
1414 if (u != v and oracle.connected(u, v))
1415 {
1416 int got = lct.path_query(nd[u], nd[v]);
1417 int expected = oracle.path_max(u, v);
1419 << "path_max mismatch at op=" << op
1420 << " u=" << u << " v=" << v;
1421 }
1422 else
1423 {
1424 EXPECT_EQ(lct.connected(nd[u], nd[v]),
1425 oracle.connected(u, v));
1426 }
1427 }
1428 }
1429}
1430
1431// ===================================================================
1432// L. export_to_tree_node — vertex-only LCT
1433// ===================================================================
1434
1436{
1437 // path: 0-1-2-3-4
1438 constexpr int N = 5;
1439 std::vector<Link_Cut_Tree::Node *> nd(N);
1440 for (int i = 0; i < N; ++i)
1441 nd[i] = lct.make_vertex(i * 10);
1442 for (int i = 0; i + 1 < N; ++i)
1443 lct.link(nd[i], nd[i + 1]);
1444
1445 auto * tree = lct.export_to_tree_node(nd[0]);
1446
1447 // root should have value 0
1448 EXPECT_EQ(tree->get_key(), 0);
1449 EXPECT_TRUE(tree->is_root());
1450
1451 // root has one child (1), which has one child (2), etc.
1452 auto * c = tree->get_left_child();
1453 ASSERT_NE(c, nullptr);
1454 EXPECT_EQ(c->get_key(), 10);
1455
1456 c = c->get_left_child();
1457 ASSERT_NE(c, nullptr);
1458 EXPECT_EQ(c->get_key(), 20);
1459
1460 c = c->get_left_child();
1461 ASSERT_NE(c, nullptr);
1462 EXPECT_EQ(c->get_key(), 30);
1463
1464 c = c->get_left_child();
1465 ASSERT_NE(c, nullptr);
1466 EXPECT_EQ(c->get_key(), 40);
1467 EXPECT_TRUE(c->is_leaf());
1468
1469 destroy_tree(tree);
1470}
1471
1473{
1474 // 0
1475 // / | \ .
1476 // 1 2 3
1477 auto * center = lct.make_vertex(100);
1478 auto * l1 = lct.make_vertex(10);
1479 auto * l2 = lct.make_vertex(20);
1480 auto * l3 = lct.make_vertex(30);
1481
1482 lct.make_root(center);
1483 lct.link(l1, center);
1484 lct.link(l2, center);
1485 lct.link(l3, center);
1486
1487 auto * tree = lct.export_to_tree_node(center);
1488 EXPECT_EQ(tree->get_key(), 100);
1489 EXPECT_TRUE(tree->is_root());
1490 EXPECT_FALSE(tree->is_leaf());
1491
1492 // Collect children values
1493 std::vector<int> child_vals;
1494 for (auto * c = tree->get_left_child(); c != nullptr;
1495 c = c->get_right_sibling())
1496 {
1497 child_vals.push_back(c->get_key());
1498 EXPECT_TRUE(c->is_leaf());
1499 }
1500
1501 std::sort(child_vals.begin(), child_vals.end());
1502 ASSERT_EQ(child_vals.size(), 3u);
1503 EXPECT_EQ(child_vals[0], 10);
1504 EXPECT_EQ(child_vals[1], 20);
1505 EXPECT_EQ(child_vals[2], 30);
1506
1507 destroy_tree(tree);
1508}
1509
1510// ===================================================================
1511// M. export_to_tree_node — edge-weighted LCT
1512// ===================================================================
1513
1515{
1516 // a --(5)-- b --(3)-- c --(7)-- d
1517 auto * a = lct.make_vertex(0);
1518 auto * b = lct.make_vertex(1);
1519 auto * c = lct.make_vertex(2);
1520 auto * d = lct.make_vertex(3);
1521
1522 lct.link(a, b, 5);
1523 lct.link(b, c, 3);
1524 lct.link(c, d, 7);
1525
1526 auto * tree = lct.export_to_tree_node(a);
1527
1528 // Root = a, parent_edge = identity (INT_MIN for MaxMonoid)
1529 EXPECT_EQ(tree->get_key().lct_node, a);
1530 EXPECT_TRUE(tree->is_root());
1531
1532 // a's only child is b with edge weight 5
1533 auto * cb = tree->get_left_child();
1534 ASSERT_NE(cb, nullptr);
1535 EXPECT_EQ(cb->get_key().lct_node, b);
1536 EXPECT_EQ(cb->get_key().vertex_value, 1);
1537 EXPECT_EQ(cb->get_key().parent_edge, 5);
1538
1539 // b's only child is c with edge weight 3
1540 auto * cc = cb->get_left_child();
1541 ASSERT_NE(cc, nullptr);
1542 EXPECT_EQ(cc->get_key().lct_node, c);
1543 EXPECT_EQ(cc->get_key().vertex_value, 2);
1544 EXPECT_EQ(cc->get_key().parent_edge, 3);
1545
1546 // c's only child is d with edge weight 7
1547 auto * cd = cc->get_left_child();
1548 ASSERT_NE(cd, nullptr);
1549 EXPECT_EQ(cd->get_key().lct_node, d);
1550 EXPECT_EQ(cd->get_key().vertex_value, 3);
1551 EXPECT_EQ(cd->get_key().parent_edge, 7);
1552 EXPECT_TRUE(cd->is_leaf());
1553
1554 destroy_tree(tree);
1555}
1556
1558{
1559 // center
1560 // / | \ .
1561 // x y z
1562 // (10)(20)(30)
1563 auto * center = lct.make_vertex(0);
1564 auto * x = lct.make_vertex(1);
1565 auto * y = lct.make_vertex(2);
1566 auto * z = lct.make_vertex(3);
1567
1568 lct.link(x, center, 10);
1569 lct.link(y, center, 20);
1570 lct.link(z, center, 30);
1571
1572 auto * tree = lct.export_to_tree_node(center);
1573 EXPECT_EQ(tree->get_key().lct_node, center);
1574
1575 std::vector<int> child_weights;
1576 for (auto * c = tree->get_left_child(); c != nullptr;
1577 c = c->get_right_sibling())
1578 child_weights.push_back(c->get_key().parent_edge);
1579
1580 std::sort(child_weights.begin(), child_weights.end());
1581 ASSERT_EQ(child_weights.size(), 3u);
1582 EXPECT_EQ(child_weights[0], 10);
1583 EXPECT_EQ(child_weights[1], 20);
1584 EXPECT_EQ(child_weights[2], 30);
1585
1586 destroy_tree(tree);
1587}
1588
1589// ===================================================================
1590// N. Gen_Link_Cut_Tree_WithEdges — wrapper-specific contracts
1591// ===================================================================
1592
1594{
1595 auto * a = lct.make_vertex(0);
1596 auto * b = lct.make_vertex(1);
1597 auto * c = lct.make_vertex(2);
1598
1599 EXPECT_EQ(lct.num_edges(), 0u);
1600 EXPECT_EQ(lct.num_components(), 3u);
1601
1602 lct.link(a, b, 1);
1603 EXPECT_EQ(lct.num_edges(), 1u);
1604 EXPECT_EQ(lct.num_components(), 2u);
1605
1606 lct.link(b, c, 2);
1607 EXPECT_EQ(lct.num_edges(), 2u);
1608 EXPECT_EQ(lct.num_components(), 1u);
1609}
1610
1612{
1613 auto * a = lct.make_vertex(0);
1614 auto * b = lct.make_vertex(1);
1615 auto * c = lct.make_vertex(2);
1616
1617 lct.link(a, b, 10);
1618 lct.link(b, c, 20);
1619 EXPECT_EQ(lct.num_edges(), 2u);
1620 EXPECT_EQ(lct.num_components(), 1u);
1621
1622 lct.cut(a, b);
1623 EXPECT_EQ(lct.num_edges(), 1u);
1624 EXPECT_EQ(lct.num_components(), 2u);
1625
1626 lct.cut(b, c);
1627 EXPECT_EQ(lct.num_edges(), 0u);
1628 EXPECT_EQ(lct.num_components(), 3u);
1629}
1630
1632{
1633 auto * a = lct.make_vertex(0);
1634 auto * b = lct.make_vertex(1);
1635 auto * c = lct.make_vertex(2);
1636 auto * d = lct.make_vertex(3);
1637
1638 lct.link(a, b, 1);
1639 lct.link(b, c, 2);
1640 lct.link(c, d, 3);
1641
1642 // path a-b-c-d has 4 nodes
1643 EXPECT_EQ(lct.path_size(a, d), 4u);
1644 EXPECT_EQ(lct.path_size(a, b), 2u);
1645 EXPECT_EQ(lct.path_size(b, d), 3u);
1646}
1647
1649{
1650 auto * a = lct.make_vertex(0);
1651 auto * b = lct.make_vertex(1);
1652 auto * c = lct.make_vertex(2);
1653
1654 lct.link(a, b, 5);
1655 lct.link(b, c, 7);
1656
1657 // Initial root is arbitrary; after make_root(c) find_root should return c.
1658 lct.make_root(c);
1659 EXPECT_EQ(lct.find_root(a), c);
1660 EXPECT_EQ(lct.find_root(b), c);
1661 EXPECT_EQ(lct.find_root(c), c);
1662
1663 lct.make_root(a);
1664 EXPECT_EQ(lct.find_root(c), a);
1665}
1666
1667// Regression: passing a handle from a different instance must be rejected.
1669{
1672
1673 auto * u1 = lct1.make_vertex(1);
1674 auto * v1 = lct1.make_vertex(3);
1675 auto * u2 = lct2.make_vertex(2);
1676
1677 EXPECT_THROW(lct1.connected(u1, u2), std::domain_error);
1678 EXPECT_THROW(lct1.set_vertex_val(u2, 9), std::domain_error);
1679 EXPECT_THROW(lct1.link(u1, u2, 4), std::domain_error);
1680 EXPECT_THROW(lct1.path_query(u1, u2), std::domain_error);
1681 EXPECT_THROW(lct1.make_root(u2), std::domain_error);
1682 EXPECT_THROW(lct1.find_root(u2), std::domain_error);
1683 EXPECT_THROW(lct1.path_size(u1, u2), std::domain_error);
1684 EXPECT_THROW(destroy_tree(lct1.export_to_tree_node(u2)), std::domain_error);
1685
1686 lct1.link(u1, v1, 5);
1687 EXPECT_THROW(lct1.path_query(v1, u2), std::domain_error);
1688 EXPECT_THROW(lct1.path_size(v1, u2), std::domain_error);
1689}
1690
1691int main(int argc, char * argv[])
1692{
1693 ::testing::InitGoogleTest(&argc, argv);
1694 return RUN_ALL_TESTS();
1695}
WeightedDigraph::Node Node
long double w
Definition btreepic.C:153
Gen_Link_Cut_Tree< long long, SumMonoid< long long >, AssignLazyTag< long long > > lct
Gen_Link_Cut_Tree_WithEdges< int, int, MaxMonoid< int > > lct
Gen_Link_Cut_Tree< int, GcdMonoid< int > > lct
Gen_Link_Cut_Tree< long long, SumMonoid< long long >, AddLazyTag< long long > > lct
Gen_Link_Cut_Tree< int, MaxMonoid< int > > lct
Gen_Link_Cut_Tree< int, MinMonoid< int > > lct
Gen_Link_Cut_Tree< long long, ProductMonoid< long long > > lct
Gen_Link_Cut_Tree< int, SumMonoid< int > > lct
Gen_Link_Cut_Tree< int, XorMonoid< int > > lct
#define TEST(name)
static mt19937 rng
#define N
Definition fib.C:294
void destroy_tree(Node *root)
Destroys (frees memory) the tree whose root is root.
static mpfr_t y
Definition mpfr_mul_d.c:3
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.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
#define LL
Definition ran_array.c:24
Additive lazy tag: adds a delta to every node on a path.
Payload for the assignment lazy tag.
Assignment lazy tag: sets every node on a path to a fixed value.
DynList< char > l3
DynList< int > l1
DynList< int > l2
Dnode< int > Test
Definition testDnode.C:37
gsl_rng * r