TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
persistent_seg_tree_lazy_prop.cpp
Go to the documentation of this file.
1
25#include <cstdint>
26#include <iostream>
27#include <memory>
28#include <vector>
29
34namespace range_queries {
35
41 private:
42 class Node {
43 public:
44 std::shared_ptr<Node> left = nullptr;
45 std::shared_ptr<Node> right = nullptr;
46 int64_t val = 0,
47 prop = 0;
51 };
52
53 uint32_t n = 0;
54 std::vector<std::shared_ptr<Node>>
55 ptrs{};
58 std::vector<int64_t> vec{};
60
66 std::shared_ptr<Node> newKid(std::shared_ptr<Node> const &curr) {
67 auto newNode = std::make_shared<Node>(Node());
68 newNode->left = curr->left;
69 newNode->right = curr->right;
70 newNode->prop = curr->prop;
71 newNode->val = curr->val;
72 return newNode;
73 }
74
84 void lazy(const uint32_t &i, const uint32_t &j,
85 std::shared_ptr<Node> const &curr) {
86 if (!curr->prop) {
87 return;
88 }
89 curr->val += (j - i + 1) * curr->prop;
90 if (i != j) {
91 curr->left = newKid(curr->left);
92 curr->right = newKid(curr->right);
93 curr->left->prop += curr->prop;
94 curr->right->prop += curr->prop;
95 }
96 curr->prop = 0;
97 }
98
107 std::shared_ptr<Node> construct(const uint32_t &i, const uint32_t &j) {
108 auto newNode = std::make_shared<Node>(Node());
109 if (i == j) {
110 newNode->val = vec[i];
111 } else {
112 uint32_t mid = i + (j - i) / 2;
113 auto leftt = construct(i, mid);
114 auto right = construct(mid + 1, j);
115 newNode->val = leftt->val + right->val;
116 newNode->left = leftt;
117 newNode->right = right;
118 }
119 return newNode;
120 }
121
136 std::shared_ptr<Node> update(const uint32_t &i, const uint32_t &j,
137 const uint32_t &l, const uint32_t &r,
138 const int64_t &value,
139 std::shared_ptr<Node> const &curr) {
140 lazy(i, j, curr);
141 if (i >= l && j <= r) {
142 std::shared_ptr<Node> newNode = newKid(curr);
143 newNode->prop += value;
144 lazy(i, j, newNode);
145 return newNode;
146 }
147 if (i > r || j < l) {
148 return curr;
149 }
150 auto newNode = std::make_shared<Node>(Node());
151 uint32_t mid = i + (j - i) / 2;
152 newNode->left = update(i, mid, l, r, value, curr->left);
153 newNode->right = update(mid + 1, j, l, r, value, curr->right);
154 newNode->val = newNode->left->val + newNode->right->val;
155 return newNode;
156 }
157
172 int64_t query(const uint32_t &i, const uint32_t &j, const uint32_t &l,
173 const uint32_t &r, std::shared_ptr<Node> const &curr) {
174 lazy(i, j, curr);
175 if (j < l || r < i) {
176 return 0;
177 }
178 if (i >= l && j <= r) {
179 return curr->val;
180 }
181 uint32_t mid = i + (j - i) / 2;
182 return query(i, mid, l, r, curr->left) +
183 query(mid + 1, j, l, r, curr->right);
184 }
185
190 public:
198 void construct(const std::vector<int64_t>
199 &vec) // the segment tree will be built from the values
200 // in "vec", "vec" is 0 indexed
201 {
202 if (vec.empty()) {
203 return;
204 }
205 n = vec.size();
206 this->vec = vec;
207 auto root = construct(0, n - 1);
208 ptrs.push_back(root);
209 }
210
220 void update(const uint32_t &l, const uint32_t &r,
221 const int64_t
222 &value) // all elements from index "l" to index "r" would
223 // by updated by "value", "l" and "r" are 0 indexed
224 {
225 ptrs.push_back(update(
226 0, n - 1, l, r, value,
227 ptrs[ptrs.size() -
228 1])); // saving the root pointer to the new segment tree
229 }
230
242 int64_t query(
243 const uint32_t &l, const uint32_t &r,
244 const uint32_t
245 &version) // querying the range from "l" to "r" in a segment tree
246 // after "version" updates, "l" and "r" are 0 indexed
247 {
248 return query(0, n - 1, l, r, ptrs[version]);
249 }
250
256 uint32_t size() // returns the number of segment trees (versions) , the
257 // number of updates done so far = returned value - 1
258 // ,because one of the trees is the original segment tree
259 {
260 return ptrs.size();
261 }
262};
263} // namespace range_queries
264
269static void test() {
270 std::vector<int64_t> arr = {-5, 2, 3, 11, -2, 7, 0, 1};
272 std::cout << "Elements before any updates are {";
273 for (uint32_t i = 0; i < arr.size(); ++i) {
274 std::cout << arr[i];
275 if (i != arr.size() - 1) {
276 std::cout << ",";
277 }
278 }
279 std::cout << "}\n";
280 tree.construct(
281 arr); // constructing the original segment tree (version = 0)
282 std::cout << "Querying range sum on version 0 from index 2 to 4 = 3+11-2 = "
283 << tree.query(2, 4, 0) << '\n';
284 std::cout
285 << "Subtract 7 from all elements from index 1 to index 5 inclusive\n";
286 tree.update(1, 5, -7); // subtracting 7 from index 1 to index 5
287 std::cout << "Elements of the segment tree whose version = 1 (after 1 "
288 "update) are {";
289 for (uint32_t i = 0; i < arr.size(); ++i) {
290 std::cout << tree.query(i, i, 1);
291 if (i != arr.size() - 1) {
292 std::cout << ",";
293 }
294 }
295 std::cout << "}\n";
296 std::cout << "Add 10 to all elements from index 0 to index 7 inclusive\n";
297 tree.update(0, 7, 10); // adding 10 to all elements
298 std::cout << "Elements of the segment tree whose version = 2 (after 2 "
299 "updates) are {";
300 for (uint32_t i = 0; i < arr.size(); ++i) {
301 std::cout << tree.query(i, i, 2);
302 if (i != arr.size() - 1) {
303 std::cout << ",";
304 }
305 }
306 std::cout << "}\n";
307 std::cout << "Number of segment trees (versions) now = " << tree.size()
308 << '\n';
309 std::cout << "Querying range sum on version 0 from index 3 to 5 = 11-2+7 = "
310 << tree.query(3, 5, 0) << '\n';
311 std::cout << "Querying range sum on version 1 from index 3 to 5 = 4-9+0 = "
312 << tree.query(3, 5, 1) << '\n';
313}
314
319int main() {
320 test(); // run self-test implementations
321 return 0;
322}
std::shared_ptr< Node > right
pointer to the left node
Range query here is range sum, but the code can be modified to make different queries like range max ...
std::shared_ptr< Node > newKid(std::shared_ptr< Node > const &curr)
Creating a new node with the same values of curr node.
uint32_t size()
Getting the number of versions after updates so far which is equal to the size of the pointers vector...
std::vector< std::shared_ptr< Node > > ptrs
number of elements/leaf nodes in the segment tree
std::shared_ptr< Node > update(const uint32_t &i, const uint32_t &j, const uint32_t &l, const uint32_t &r, const int64_t &value, std::shared_ptr< Node > const &curr)
Doing range update, checking at every node if it has some value to be propagated. All nodes affected ...
std::shared_ptr< Node > construct(const uint32_t &i, const uint32_t &j)
Constructing the segment tree with the early passed vector. Every call creates a node to hold the sum...
void construct(const std::vector< int64_t > &vec)
Constructing the segment tree with the values in the passed vector. Returned root pointer is pushed i...
void lazy(const uint32_t &i, const uint32_t &j, std::shared_ptr< Node > const &curr)
If there is some value to be propagated to the passed node, value is added to the node and the childr...
int64_t query(const uint32_t &l, const uint32_t &r, const uint32_t &version)
Querying the range from index l to index r, getting the sum of the elements whose index x satisfies l...
int64_t query(const uint32_t &i, const uint32_t &j, const uint32_t &l, const uint32_t &r, std::shared_ptr< Node > const &curr)
Querying the range from index l to index r, checking at every node if it has some value to be propaga...
void update(const uint32_t &l, const uint32_t &r, const int64_t &value)
Doing range update by passing the left and right indexes of the range as well as the value to be adde...
for std::vector
static void test()
Test implementations.
int main()
Main function.