Algorithms_in_C++ 1.0.0
Set of algorithms implemented in C++.
Loading...
Searching...
No Matches
segtree.cpp File Reference

Implementation of [Segment Tree] (https://en.wikipedia.org/wiki/Segment_tree) data structure. More...

#include <cassert>
#include <cmath>
#include <iostream>
#include <vector>
Include dependency graph for segtree.cpp:

Functions

void ConsTree (const std::vector< int64_t > &arr, std::vector< int64_t > *segtree, uint64_t low, uint64_t high, uint64_t pos)
 for std::vector
 
int64_t query (std::vector< int64_t > *segtree, std::vector< int64_t > *lazy, uint64_t qlow, uint64_t qhigh, uint64_t low, uint64_t high, uint64_t pos)
 Returns the sum of all elements in a range.
 
void update (std::vector< int64_t > *segtree, std::vector< int64_t > *lazy, int64_t start, int64_t end, int64_t delta, uint64_t low, uint64_t high, uint64_t pos)
 Updates a range of the segment tree.
 
static void test ()
 Self-test implementation.
 
int main ()
 Main function.
 

Detailed Description

Implementation of [Segment Tree] (https://en.wikipedia.org/wiki/Segment_tree) data structure.

A segment tree, also known as a statistic tree, is a tree data structure used for storing information about intervals, or segments. Its classical version allows querying which of the stored segments contain a given point, but our modification allows us to perform (query) any binary operation on any range in the array in O(logN) time. Here, we have used addition (+). For range updates, we have used lazy propagation.

  • Space Complexity : O(NlogN)
  • Build Time Complexity : O(NlogN)
  • Query Time Complexity : O(logN)
    Author
    Madhav Gaba
    Soham Roy

Function Documentation

◆ ConsTree()

void ConsTree ( const std::vector< int64_t > & arr,
std::vector< int64_t > * segtree,
uint64_t low,
uint64_t high,
uint64_t pos )

for std::vector

for assert for log2 for IO operations

Constructs the initial segment tree

Parameters
arrinput to construct the tree out of
segtreethe segment tree
lowinclusive lowest index of arr to begin at
highinclusive highest index of arr to end at
posindex of segtree to fill (eg. root node)
Returns
void
38 {
39 if (low == high) {
40 (*segtree)[pos] = arr[low];
41 return;
42 }
43
44 uint64_t mid = (low + high) / 2;
45 ConsTree(arr, segtree, low, mid, 2 * pos + 1);
46 ConsTree(arr, segtree, mid + 1, high, 2 * pos + 2);
47 (*segtree)[pos] = (*segtree)[2 * pos + 1] + (*segtree)[2 * pos + 2];
48}
void ConsTree(const std::vector< int64_t > &arr, std::vector< int64_t > *segtree, uint64_t low, uint64_t high, uint64_t pos)
for std::vector
Definition segtree.cpp:37
Here is the call graph for this function:

◆ main()

int main ( void )

Main function.

Returns
0 on exit
167 {
168 test(); // run self-test implementations
169
170 std::cout << "Enter number of elements: ";
171
172 uint64_t n = 0;
173 std::cin >> n;
174
175 auto max = static_cast<uint64_t>(2 * pow(2, ceil(log2(n))) - 1);
176 std::vector<int64_t> arr(n), lazy(max), segtree(max);
177
178 int choice = 0;
179 std::cout << "\nDo you wish to enter each number?:\n"
180 "1: Yes\n"
181 "0: No (default initialize them to 0)\n";
182
183 std::cin >> choice;
184 if (choice == 1) {
185 std::cout << "Enter " << n << " numbers:\n";
186 for (int i = 1; i <= n; i++) {
187 std::cout << i << ": ";
188 std::cin >> arr[i];
189 }
190 }
191
192 ConsTree(arr, &segtree, 0, n - 1, 0);
193
194 do {
195 std::cout << "\nMake your choice:\n"
196 "1: Range update (input)\n"
197 "2: Range query (output)\n"
198 "0: Exit\n";
199 std::cin >> choice;
200
201 if (choice == 1) {
202 std::cout << "Enter 1-indexed lower bound, upper bound & value:\n";
203
204 uint64_t p = 1, q = 1, v = 0;
205 std::cin >> p >> q >> v;
206 update(&segtree, &lazy, p - 1, q - 1, v, 0, n - 1, 0);
207 } else if (choice == 2) {
208 std::cout << "Enter 1-indexed lower bound & upper bound:\n";
209
210 uint64_t p = 1, q = 1;
211 std::cin >> p >> q;
212 std::cout << query(&segtree, &lazy, p - 1, q - 1, 0, n - 1, 0);
213 std::cout << "\n";
214 }
215 } while (choice > 0);
216
217 return 0;
218}
T ceil(T... args)
T max(T... args)
T pow(T... args)
int64_t query(std::vector< int64_t > *segtree, std::vector< int64_t > *lazy, uint64_t qlow, uint64_t qhigh, uint64_t low, uint64_t high, uint64_t pos)
Returns the sum of all elements in a range.
Definition segtree.cpp:62
static void test()
Self-test implementation.
Definition segtree.cpp:146
void update(std::vector< int64_t > *segtree, std::vector< int64_t > *lazy, int64_t start, int64_t end, int64_t delta, uint64_t low, uint64_t high, uint64_t pos)
Updates a range of the segment tree.
Definition segtree.cpp:102
Here is the call graph for this function:

◆ query()

int64_t query ( std::vector< int64_t > * segtree,
std::vector< int64_t > * lazy,
uint64_t qlow,
uint64_t qhigh,
uint64_t low,
uint64_t high,
uint64_t pos )

Returns the sum of all elements in a range.

Parameters
segtreethe segment tree
lazyfor lazy propagation
qlowlower index of the required query
qhighhigher index of the required query
lowlower index of query for this function call
highhigher index of query for this function call
posindex of segtree to consider (eg. root node)
Returns
result of the range query for this function call
64 {
65 if (low > high || qlow > high || low > qhigh) {
66 return 0;
67 }
68
69 if ((*lazy)[pos] != 0) {
70 (*segtree)[pos] += (*lazy)[pos] * (high - low + 1);
71
72 if (low != high) {
73 (*lazy)[2 * pos + 1] += (*lazy)[pos];
74 (*lazy)[2 * pos + 2] += (*lazy)[pos];
75 }
76 (*lazy)[pos] = 0;
77 }
78
79 if (qlow <= low && qhigh >= high) {
80 return (*segtree)[pos];
81 }
82
83 uint64_t mid = (low + high) / 2;
84
85 return query(segtree, lazy, qlow, qhigh, low, mid, 2 * pos + 1) +
86 query(segtree, lazy, qlow, qhigh, mid + 1, high, 2 * pos + 2);
87}
Here is the call graph for this function:

◆ test()

static void test ( )
static

Self-test implementation.

Returns
void
146 {
147 auto max = static_cast<int64_t>(2 * pow(2, ceil(log2(7))) - 1);
148 assert(max == 15);
149
150 std::vector<int64_t> arr{1, 2, 3, 4, 5, 6, 7}, lazy(max), segtree(max);
151 ConsTree(arr, &segtree, 0, 7 - 1, 0);
152
153 assert(query(&segtree, &lazy, 1, 5, 0, 7 - 1, 0) == 2 + 3 + 4 + 5 + 6);
154
155 update(&segtree, &lazy, 2, 4, 1, 0, 7 - 1, 0);
156 assert(query(&segtree, &lazy, 1, 5, 0, 7 - 1, 0) == 2 + 4 + 5 + 6 + 6);
157
158 update(&segtree, &lazy, 0, 6, -2, 0, 7 - 1, 0);
159 assert(query(&segtree, &lazy, 0, 4, 0, 7 - 1, 0) == -1 + 0 + 2 + 3 + 4);
160}
Here is the call graph for this function:

◆ update()

void update ( std::vector< int64_t > * segtree,
std::vector< int64_t > * lazy,
int64_t start,
int64_t end,
int64_t delta,
uint64_t low,
uint64_t high,
uint64_t pos )

Updates a range of the segment tree.

Parameters
segtreethe segment tree
lazyfor lazy propagation
startlower index of the required query
endhigher index of the required query
deltainteger to add to each element of the range
lowlower index of query for this function call
highhigher index of query for this function call
posindex of segtree to consider (eg. root node)
Returns
void
104 {
105 if (low > high) {
106 return;
107 }
108
109 if ((*lazy)[pos] != 0) {
110 (*segtree)[pos] += (*lazy)[pos] * (high - low + 1);
111
112 if (low != high) {
113 (*lazy)[2 * pos + 1] += (*lazy)[pos];
114 (*lazy)[2 * pos + 2] += (*lazy)[pos];
115 }
116 (*lazy)[pos] = 0;
117 }
118
119 if (start > high || end < low) {
120 return;
121 }
122
123 if (start <= low && end >= high) {
124 (*segtree)[pos] += delta * (high - low + 1);
125
126 if (low != high) {
127 (*lazy)[2 * pos + 1] += delta;
128 (*lazy)[2 * pos + 2] += delta;
129 }
130
131 return;
132 }
133
134 uint64_t mid = (low + high) / 2;
135
136 update(segtree, lazy, start, end, delta, low, mid, 2 * pos + 1);
137 update(segtree, lazy, start, end, delta, mid + 1, high, 2 * pos + 2);
138 (*segtree)[pos] = (*segtree)[2 * pos + 1] + (*segtree)[2 * pos + 2];
139}
Here is the call graph for this function: