persistent_seg_tree_lazy_prop.cpp File Reference

Persistent segment tree with range updates (lazy propagation) More...

`#include <iostream>`
`#include <memory>`
`#include <vector>`
Include dependency graph for persistent_seg_tree_lazy_prop.cpp:

## Classes

class | range_queries::perSegTree
| Range query here is range sum, but the code can be modified to make different queries like range max or min. More...
class | range_queries::perSegTree::Node

## Namespaces

| range_queries
| Algorithms and Data Structures that support range queries and updates.

## Functions

static void | test ()
| Test implementations. More...
int | main ()
| Main function. More...

## Detailed Description

Persistent segment tree with range updates (lazy propagation)

A normal segment tree facilitates making point updates and range queries in logarithmic time. Lazy propagation preserves the logarithmic time with range updates. So, a segment tree with lazy propagation enables doing range updates and range queries in logarithmic time, but it doesn't save any information about itself before the last update. A persistent data structure always preserves the previous version of itself when it is modified. That is, a new version of the segment tree is generated after every update. It saves all previous versions of itself (before every update) to facilitate doing range queries in any version. More memory is used ,but the logarithmic time is preserved because the new version points to the same nodes, that the previous version points to, that are not affected by the update. That is, only the nodes that are affected by the update and their ancestors are copied. The rest is copied using lazy propagation in the next queries. Thus preserving the logarithmic time because the number of nodes copied after any update is logarithmic.

Author
  Magdy Sedra

## Function Documentation

## main()

int main | ( | void |  | ) |

Main function.

Returns
  0 on exit

{
test(); // run self-test implementations
return 0;
}
test
static void test()
Test implementations.
Definition: persistent_seg_tree_lazy_prop.cpp:268
Here is the call graph for this function:

## test()

static void test | ( |  | ) |

static

Test implementations.

Returns
  void

{
std::vector<int64_t> arr = {-5, 2, 3, 11, -2, 7, 0, 1};
range_queries::perSegTree tree;
std::cout << "Elements before any updates are {";
for (uint32_t i = 0; i < arr.size(); ++i) {
std::cout << arr[i];
if (i != arr.size() - 1) {
std::cout << ",";
}
}
std::cout << "}\n";
tree.construct(
arr); // constructing the original segment tree (version = 0)
std::cout << "Querying range sum on version 0 from index 2 to 4 = 3+11-2 = "
<< tree.query(2, 4, 0) << '\n';
std::cout
<< "Subtract 7 from all elements from index 1 to index 5 inclusive\n";
tree.update(1, 5, -7); // subtracting 7 from index 1 to index 5
std::cout << "Elements of the segment tree whose version = 1 (after 1 "
"update) are {";
for (uint32_t i = 0; i < arr.size(); ++i) {
std::cout << tree.query(i, i, 1);
if (i != arr.size() - 1) {
std::cout << ",";
}
}
std::cout << "}\n";
std::cout << "Add 10 to all elements from index 0 to index 7 inclusive\n";
tree.update(0, 7, 10); // adding 10 to all elements
std::cout << "Elements of the segment tree whose version = 2 (after 2 "
"updates) are {";
for (uint32_t i = 0; i < arr.size(); ++i) {
std::cout << tree.query(i, i, 2);
if (i != arr.size() - 1) {
std::cout << ",";
}
}
std::cout << "}\n";
std::cout << "Number of segment trees (versions) now = " << tree.size()
<< '\n';
std::cout << "Querying range sum on version 0 from index 3 to 5 = 11-2+7 = "
<< tree.query(3, 5, 0) << '\n';
std::cout << "Querying range sum on version 1 from index 3 to 5 = 4-9+0 = "
<< tree.query(3, 5, 1) << '\n';
}
std::cout
range_queries::perSegTree
Range query here is range sum, but the code can be modified to make different queries like range max ...
Definition: persistent_seg_tree_lazy_prop.cpp:39
range_queries::perSegTree::size
uint32_t size()
Getting the number of versions after updates so far which is equal to the size of the pointers vector...
Definition: persistent_seg_tree_lazy_prop.cpp:255
range_queries::perSegTree::construct
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...
Definition: persistent_seg_tree_lazy_prop.cpp:106
range_queries::perSegTree::query
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...
Definition: persistent_seg_tree_lazy_prop.cpp:171
range_queries::perSegTree::update
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 ...
Definition: persistent_seg_tree_lazy_prop.cpp:135
std::vector::size
T size(T... args)
std::vector< int64_t >
Here is the call graph for this function: