You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have provided the overview and implementation of a much simpler range sum query function, which does not require splitting the query.
I have explicitly outlined the three cases that may arise while processing a range sum query and the code directly reflects these cases.
This implementation is much more beginner friendly and intuitive.
Copy file name to clipboardExpand all lines: src/data_structures/segment_tree.md
+12-21Lines changed: 12 additions & 21 deletions
Original file line number
Diff line number
Diff line change
@@ -84,22 +84,14 @@ For now we are going to answer sum queries. As an input we receive two integers
84
84
85
85
To do this, we will traverse the Segment Tree and use the precomputed sums of the segments.
86
86
Let's assume that we are currently at the vertex that covers the segment $a[tl \dots tr]$.
87
-
There are three possible cases.
87
+
There are three possible cases:
88
+
1. $[tl \dots tr]$ is completely contained in $[l \dots r]$ : In this case, we know that the sum of this segment will surely be a part of the final answer, so we return this sum.
89
+
2. $[tl \dots tr]$ partially covers $[l \dots r]$ : In this case, we cannot include this vertex's sum and we must explore both the left and right children. First we go to the left child($[tl \dots tm]$), compute a partial answer for this vertex (i.e. the sum of values of the intersection between the segment of the query and the segment of the left child), then go to the right child($[tm + 1 \dots tr]$, compute the partial answer using that vertex, and then combine the answers by adding them.
90
+
3. There is no intersection between $[tl \dots tr]$ and $[l \dots r]$ : This segment does not contribute to the sum, so we return zero.
88
91
89
-
The easiest case is when the segment $a[l \dots r]$ is equal to the corresponding segment of the current vertex (i.e. $a[l \dots r] = a[tl \dots tr]$), then we are finished and can return the precomputed sum that is stored in the vertex.
92
+
So, processing a sum query is a function that recursively calls itself with left and right children until it finds a complete or no overlap between ranges.
90
93
91
-
Alternatively the segment of the query can fall completely into the domain of either the left or the right child.
92
-
Recall that the left child covers the segment $a[tl \dots tm]$ and the right vertex covers the segment $a[tm + 1 \dots tr]$ with $tm = (tl + tr) / 2$.
93
-
In this case we can simply go to the child vertex, which corresponding segment covers the query segment, and execute the algorithm described here with that vertex.
94
-
95
-
And then there is the last case, the query segment intersects with both children.
96
-
In this case we have no other option as to make two recursive calls, one for each child.
97
-
First we go to the left child, compute a partial answer for this vertex (i.e. the sum of values of the intersection between the segment of the query and the segment of the left child), then go to the right child, compute the partial answer using that vertex, and then combine the answers by adding them.
98
-
In other words, since the left child represents the segment $a[tl \dots tm]$ and the right child the segment $a[tm+1 \dots tr]$, we compute the sum query $a[l \dots tm]$ using the left child, and the sum query $a[tm+1 \dots r]$ using the right child.
99
-
100
-
So processing a sum query is a function that recursively calls itself once with either the left or the right child (without changing the query boundaries), or twice, once for the left and once for the right child (by splitting the query into two subqueries).
101
-
And the recursion ends, whenever the boundaries of the current query segment coincides with the boundaries of the segment of the current vertex.
102
-
In that case the answer will be the precomputed value of the sum of this segment, which is stored in the tree.
94
+
So processing a sum query is a function that recursively calls itself once with either the left or the right child (without changing the query boundaries), or twice, once for the left and once for the right child (by splitting the query into two subqueries). And the recursion ends, whenever the boundaries of the current query segment coincides with the boundaries of the segment of the current vertex. In that case the answer will be the precomputed value of the sum of this segment, which is stored in the tree.
103
95
104
96
In other words, the calculation of the query is a traversal of the tree, which spreads through all necessary branches of the tree, and uses the precomputed sum values of the segments in the tree.
105
97
@@ -202,14 +194,13 @@ In order to simplify the code, this function always does two recursive calls, ev
202
194
203
195
```{.cpp file=segment_tree_implementation_sum}
204
196
int sum(int v, int tl, int tr, int l, int r) {
205
-
if (l > r)
206
-
return 0;
207
-
if (l == tl && r == tr) {
208
-
return t[v];
209
-
}
197
+
if (tr < l || tl > r) return 0; // no overlap
198
+
if (tl >= l && tr <= r) return t[v]; // complete overlap
0 commit comments