Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
heavy_light_decomposition_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
45#include <Tree_Decomposition.H>
46#include <tpl_graph.H>
47
48#include <array>
49#include <cassert>
50#include <format>
51#include <iomanip>
52#include <iostream>
53#include <string>
54
55using namespace Aleph;
56
57namespace
58{
60 using Node = G::Node;
61
71 int brute_path_sum(const Array<int> & values,
73 size_t u,
74 size_t v)
75 {
76 int sum = 0;
77
78 while (hld.depth_of_id(u) > hld.depth_of_id(v))
79 {
80 sum += values(u);
81 u = hld.parent_id(u);
82 }
83
84 while (hld.depth_of_id(v) > hld.depth_of_id(u))
85 {
86 sum += values(v);
87 v = hld.parent_id(v);
88 }
89
90 while (u != v)
91 {
92 sum += values(u);
93 sum += values(v);
94 u = hld.parent_id(u);
95 v = hld.parent_id(v);
96 }
97
98 return sum + values(u);
99 }
100
109 int brute_subtree_sum(const Array<int> & values,
111 const size_t u)
112 {
113 int sum = 0;
114 for (size_t v = 0; v < hld.size(); ++v)
115 if (hld.is_ancestor_id(u, v))
116 sum += values(v);
117
118 return sum;
119 }
120}
121
133int main()
134{
135 G g;
136
137 // [Central]
138 // / | \\ (edge)
139 // [North] [West] [South]
140 // / \ |
141 // [N-A] [N-B] [S-A]
142 // / \\ (edge)
143 // [S-A1] [S-A2]
144
145 auto * central = g.insert_node(50);
146 auto * north = g.insert_node(30);
147 auto * west = g.insert_node(20);
148 auto * south = g.insert_node(25);
149 auto * na = g.insert_node(10);
150 auto * nb = g.insert_node(12);
151 auto * sa = g.insert_node(18);
152 auto * sa1 = g.insert_node(7);
153 auto * sa2 = g.insert_node(9);
154
155 g.insert_arc(central, north, 1);
156 g.insert_arc(central, west, 1);
157 g.insert_arc(central, south, 1);
158 g.insert_arc(north, na, 1);
159 g.insert_arc(north, nb, 1);
160 g.insert_arc(south, sa, 1);
161 g.insert_arc(sa, sa1, 1);
162 g.insert_arc(sa, sa2, 1);
163
164 const std::array<const char *, 9> labels = {
165 "Central", "North", "West", "South", "N-A",
166 "N-B", "S-A", "S-A1", "S-A2"};
167
169 const auto & hld = grid.decomposition();
170
171 auto values = Array<int>::create(hld.size());
172 for (size_t i = 0; i < hld.size(); ++i)
173 values(i) = hld.node_of(i)->get_info();
174
175 std::cout << "=== Aurora Power Grid (HLD path queries) ===\n\n";
176 std::cout << "Node mapping (id -> label, base position):\n";
177 for (size_t i = 0; i < hld.size(); ++i)
178 std::cout << std::format(" id={} {:<8} pos={}\n",
179 i, labels[i], hld.position_of_id(i));
180
181 std::cout << "\nPath maintenance cost queries:\n";
182
183 struct Query
184 {
185 Node * u;
186 Node * v;
187 const char * name;
188 };
189
190 const std::array<Query, 4> queries = {{
191 {na, nb, "N-A -> N-B"},
192 {na, sa2, "N-A -> S-A2"},
193 {west, sa1, "West -> S-A1"},
194 {central, sa2, "Central -> S-A2"}
195 }};
196
197 for (const auto & q : queries)
198 {
199 const size_t u = hld.id_of(q.u);
200 const size_t v = hld.id_of(q.v);
201
202 const int ans = grid.query_path_id(u, v);
203 const int brute = brute_path_sum(values, hld, u, v);
204
205 std::cout << std::format(" {:<18} HLD={:>3} brute={:>3}\n",
206 q.name, ans, brute);
207 assert(ans == brute);
208 }
209
210 std::cout << "\nSubtree (service area) totals:\n";
211 for (auto * x : {central, north, south, sa})
212 {
213 const size_t id = hld.id_of(x);
214 const int ans = grid.query_subtree_id(id);
215 const int brute = brute_subtree_sum(values, hld, id);
216 std::cout << std::format(" {:<8} subtree total = {:>3}\n",
217 labels[id], ans);
218 assert(ans == brute);
219 }
220
221 std::cout << "\nBudget changes (point updates):\n";
222 std::cout << " +5 to S-A2, set West to 26\n";
223
224 const size_t id_sa2 = hld.id_of(sa2);
225 const size_t id_west = hld.id_of(west);
226
227 grid.update_node_id(id_sa2, 5);
228 values(id_sa2) += 5;
229
230 grid.set_node_id(id_west, 26);
231 values(id_west) = 26;
232
233 const int after_path = grid.query_path(north, sa2);
234 const int brute_after_path = brute_path_sum(values, hld, hld.id_of(north), hld.id_of(sa2));
235 std::cout << std::format(" North -> S-A2 after update: HLD={} brute={}\n",
238
239 std::cout << "\nHow HLD splits path N-A -> S-A2 into base-array segments:\n";
240 hld.for_each_path_segment(na, sa2,
241 [&](const size_t l,
242 const size_t r,
243 const bool reversed)
244 {
245 std::cout << std::format(" segment [{}, {}] ({})\n",
246 l, r, (reversed ? "reversed" : "forward"));
247 });
248
249 std::cout << "\nAll assertions passed.\n";
250 return 0;
251}
Heavy-Light and Centroid decomposition on rooted trees represented as Aleph graphs.
WeightedDigraph::Node Node
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
Segment-tree-powered path/subtree queries over an HLD layout.
Heavy-Light Decomposition over a rooted tree represented as an Aleph graph.
Graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:428
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
_Graph_Node Node
The graph type.
Definition tpl_graph.H:432
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
int main()
Executable example demonstrating heavy-light decomposition on a small tree.
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.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
gsl_rng * r
Generic graph and digraph implementations.
DynList< int > l