//javascript Program to show segment tree to
// demonstrate lazy propagation
let MAX = 1000;
// Ideally, we should not use global
// variables and large constant-sized
// arrays, we have done it here for
// simplicity.
// To store segment tree
let tree = new Array(MAX).fill(0);
// To store pending updates
let lazy = new Array(MAX).fill(0);
// si -> index of current node in segment tree
// ss and se -> Starting and ending
// indices of elements for which current
// nodes stores sum.
// us and ue -> starting and ending indexes
// of update query
// diff -> which we need to add in the
// range us to ue
function updateRangeUtil( si,ss, se, us, ue, diff)
{
// console.log(si,ss,se,us,ue,diff);
// If lazy value is non-zero for
// current node of segment tree, then
// there are some pending updates. So,
// we need to make sure that the
// pending updates are done before
// making new updates. Because this
// value may be used by parent after
// recursive calls (See last line
// of this function)
if (lazy[si] != 0) {
// Make pending updates using
// value stored in lazy nodes
tree[si] += (se - ss + 1) * lazy[si];
// checking if it is not leaf node
// because if it is leaf node then
// we cannot go further
if (ss != se) {
// We can postpone updating
// children we don't need
// their new values now. Since
// we are not yet updating
// children of si, we need to
// set lazy flags for the children
lazy[si * 2 + 1] += lazy[si];
lazy[si * 2 + 2] += lazy[si];
}
// Set the lazy value for current
// node as 0 as it has been updated
lazy[si] = 0;
}
// out of range
if (ss > se || ss > ue || se < us)
return ;
// Current segment is fully in range
if (ss >= us && se <= ue) {
// Add the difference to
// current node
tree[si] += (se - ss + 1) * diff;
// Same logic for checking
// leaf node or not
if (ss != se) {
// This is where we store
// values in lazy nodes,
// rather than updating the
// segment tree itself Since
// we don't need these updated
// values now we postpone
// updates by storing values
// in lazy[]
lazy[si * 2 + 1] += diff;
lazy[si * 2 + 2] += diff;
}
return;
}
// If not completely in rang,
// but overlaps, recur for children,
let mid = (ss + se) / 2;
updateRangeUtil(Math.floor(si * 2 + 1), Math.floor(ss), Math.floor(mid), Math.floor(us), Math.floor(ue), Math.floor(diff));
updateRangeUtil(Math.floor(si * 2 + 2), Math.floor(mid + 1), Math.floor(se), Math.floor(us), Math.floor(ue), Math.floor(diff));
// And use the result of children
// calls to update this node
tree[si] = tree[si * 2 + 1] + tree[si * 2 + 2];
}
// Function to update a range of values
// in segment tree
// us and eu -> starting and ending
// indices of update query
// ue -> ending index of update query
// diff -> which we need to add in the
// range us to ue
function updateRange(n, us, ue, diff)
{
updateRangeUtil(0, 0, n - 1, us, ue, diff);
}
// A recursive function to get the sum of
// values in given range of the array.
// The following are parameters for this function.
// si --> Index of current node in the st.
// Initially 0 is passed as root is always
// at' index 0
// ss & se --> Starting and ending indices
// of the segment represented by current
// node, i.e., tree[si]
// qs & qe --> Starting and ending
// indices of query range
function getSumUtil( ss, se, qs, qe, si)
{
// console.log(ss,se,qs,qe,si);
// // If lazy flag is set for current
// node of segment tree, then there
// are some pending updates. So we
// need to make sure that the pending
// updates are done before
// processing the sub sum query
if (lazy[si] != 0) {
// Make pending updates to this
// node. Note that this node
// represents sum of elements in
// arr[ss..se] and all these
// elements must be increased by
// lazy[si]
tree[si] += (se - ss + 1) * lazy[si];
// Checking if it is not leaf node
// because if it is leaf node then
// we cannot go further
if (ss != se) {
// Since we are not yet
// updating children os si,
// we need to set lazy values
// for the children
lazy[si * 2 + 1] += lazy[si];
lazy[si * 2 + 2] += lazy[si];
}
// unset the lazy value for current
// node as it has been updated
lazy[si] = 0;
}
// Out of range
if (ss > se || ss > qe || se < qs)
return 0;
// At this point we are sure that
// pending lazy updates are done for
// current node. So we can return
// value
// If this segment lies in range
if (ss >= qs && se <= qe)
return tree[si];
// If a part of this segment overlaps
// with the given range
let mid = (ss + se) / 2;
return getSumUtil(Math.floor(ss), Math.floor(mid), Math.floor(qs), Math.floor(qe), Math.floor(2 * si + 1))
+ getSumUtil(Math.floor(mid + 1), Math.floor(se), Math.floor(qs), Math.floor(qe), Math.floor(2 * si + 2));
}
// Return sum of elements in range from
// index qs (query start) to qe (query end).
// It mainly uses getSumUtil()
function getSum (n, qs, qe)
{
// Check for erroneous input values
if (qs < 0 || qe > n - 1 || qs > qe) {
console.log("Invalid Input");
return -1;
}
// console.log(n,qs,qe);
return getSumUtil(0, n - 1, qs, qe, 0);
}
// A recursive function that constructs
// Segment Tree for array[ss..se].
// si is index of current node in st.
function constructSTUtil( arr, ss, se, si)
{
// console.log(arr,ss,se,si);
// Out of range as ss can never
// be greater than se
if (ss > se)
return;
// If there is one element in array,
// store it in current node of segment
// tree and return
if (ss == se) {
tree[si] = arr[ss];
return;
}
// If there are more than one elements,
// then recur for left and right
// subtrees and store the sum of
// values in this node
let mid = (ss + se) / 2;
constructSTUtil(arr, Math.floor(ss), Math.floor(mid), Math.floor(si * 2 + 1));
constructSTUtil(arr, Math.floor(mid + 1), Math.floor(se), Math.floor(si * 2 + 2));
tree[si] = tree[si * 2 + 1] + tree[si * 2 + 2];
}
// Function to construct segment tree
// from given array.This function allocates
// memory for segment tree and calls
// constructSTUtil() to fill the
// allocated memory
function constructST(arr, n)
{
// Fill the allocated memory st
constructSTUtil(arr, 0, n - 1, 0);
}
let arr = [ 1, 3, 5, 7, 9, 11 ];
let n = arr.length;
// Build segment tree from given array
constructST(arr, n);
// Print sum of values in array
// from index 1 to 3
console.log(`Sum of values in given range = ${getSum(n, 1, 3)}`);
// Add 10 to all nodes at indexes
// from 1 to 5.
updateRange(n, 1, 5, 10);
console.log(`Updated sum of values in given range = ${ getSum(n, 1, 3)}`);
// This code is contributed by ksam24000.