I'm referring to this post : https://www.geeksforgeeks.org/segment-tree-efficient-implementation/
Pasting the code here for reference. My questions are below the code.
#include <bits/stdc++.h>
using namespace std;
// limit for array size
const int N = 100000;
int n; // array size
// Max size of tree
int tree[2 * N];
// function to build the tree
void build( int arr[])
{
// insert leaf nodes in tree
for (int i=0; i<n; i++)
tree[n+i] = arr[i];
// build the tree by calculating parents
for (int i = n - 1; i > 0; --i)
tree[i] = tree[i<<1] + tree[i<<1 | 1];
}
// function to update a tree node
void updateTreeNode(int p, int value)
{
// set value at position p
tree[p+n] = value; // {Question} Why is this assigned before updating the parent index to access?
p = p+n;
// move upward and update parents
for (int i=p; i > 1; i >>= 1)
tree[i>>1] = tree[i] + tree[i^1];
}
// function to get sum on interval [l, r)
int query(int l, int r)
{
int res = 0;
// loop to find the sum in the range
for (l += n, r += n; l < r; l >>= 1, r >>= 1)
{
if (l&1)
res += tree[l++];
if (r&1)
res += tree[--r];
// {Question} What happens if !(l&1) or !(r&1) ? res is not accumulated anywhere. Isn't this wrong?
}
return res;
}
// driver program to test the above function
int main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
// n is global
n = sizeof(a)/sizeof(a[0]);
// build tree
build(a);
// print the sum in range(1,2) index-based
cout << query(1, 3)<<endl;
// modify element at 2nd index
updateTreeNode(2, 1);
// print the sum in range(1,2) index-based
cout << query(1, 3)<<endl;
return 0;
}
Questions:
Within updateTreeNode
where value is being set to parent,
why is the parent being incremented by array size after assigning the value in the tree?
Shouldn't it be before?
The original line of code this post has implemented this from reads like this:
for (tree[parent += n] = value; parent > 1; parent >>= 1)
where parent=parent+n
executes first.
Can someone help me understand why this code is still functioning properly?
Within query
which returns a sum in the interval [l, r), this code seems to add
result only for odd values of l
.
Yet, I see that the result correctly returns the sum for even-valued-intervals.
The result should be skipping accumulating even-valued intervals since there is no else <accumulate result>
, right? What am I missing?
The variable p
doesn't mean parent, it means child. In for
loop, i
is child node, and we update value of i
's parent.
tree[p+n] = value;
: update the value of leave node (node without children). Then we update value of node's parent from the leave node. tree[i>>1] = tree[i] + tree[i^1];
, tree[i>>1]
is tree[i]
' parent.
For example: the array size is 16 (the tree size is 32) and I want to update arr[8]. So I call updateTreeNode(8, value)
. First three[8+16]
is updated, which corresponds to arr[8]
. Then p
is set to 24. In for loop, we update p's parent (tree[12]), then set p to p/2 (p=12), until p doesn't have parent.
If l
and r
is even, we add the parent's value in next recurrence. That's the function of segment tree, to avoid querying each element in the interval.
For example: the array size is 16 and I want to query [8,10). In segment tree, the interval is [24,26). We don't need to add value of tree[24]
and tree[25]
, we add value of tree[12]
!