<script>
// Javascript implementation of the approach
// A utility function to get the
// middle index from corner indexes.
function getMid(s, e)
{
return s + parseInt((e - s) / 2, 10);
}
/*
* 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 segment tree. Initially
* 0 is passed as root is always
* at index 0
* ss & se --> Starting and ending
* indexes of the segment
* represented by current
* node, i.e., tree[si]
* qs & qe --> Starting and ending
* indexes of query range
*/
function getSumUtil(tree, lazy, 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]
tree[si] = (se - ss + 1) - tree[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] = 1 - lazy[si * 2 + 1];
lazy[si * 2 + 2] = 1 - lazy[si * 2 + 2];
}
// 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 (same as it was
// for query in our previous post)
// 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 = parseInt((ss + se) / 2, 10);
return getSumUtil(tree, lazy, ss, mid, qs, qe, 2 * si + 1)
+ getSumUtil(tree, lazy, mid + 1, se, qs, qe, 2 * si + 2);
}
// Return sum of elements in range from index
// qs (query start) to qe (query end). It
// mainly uses getSumUtil()
function getSum(tree, lazy, n, qs, qe)
{
// Check for erroneous input values
if (qs < 0 || qe > n - 1 || qs > qe)
{
document.write("Invalid Input");
return -1;
}
return getSumUtil(tree, lazy, 0, n - 1, qs, qe, 0);
}
/*
* si -> index of current node in segment tree
* ss and se -> Starting and ending indexes of
* elements for which current
* nodes stores sum.
* us and ue -> starting and ending indexes of
* update query
*/
function updateRangeUtil(tree, lazy, si, ss, se, us, ue)
{
// 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) - tree[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] = 1 - lazy[si * 2 + 1];
lazy[si * 2 + 2] = 1 - lazy[si * 2 + 2];
}
// 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) - tree[si];
// 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] = 1 - lazy[si * 2 + 1];
lazy[si * 2 + 2] = 1 - lazy[si * 2 + 2];
}
return;
}
// If not completely in rang, but overlaps,
// recur for children
let mid = parseInt((ss + se) / 2, 10);
updateRangeUtil(tree, lazy, si * 2 + 1, ss, mid, us, ue);
updateRangeUtil(tree, lazy, si * 2 + 2, mid + 1, se, us, ue);
// 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 indexes
* of update query
* ue -> ending index of update query
* diff -> which we need to add in the range
* us to ue
*/
function updateRange(tree, lazy, n, us, ue)
{
updateRangeUtil(tree, lazy, 0, 0, n - 1, us, ue);
}
// A recursive function that constructs
// Segment Tree for array[ss..se]. si is
// index of current node in segment tree st
function constructSTUtil(arr, ss, se, tree, si)
{
// 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 arr[ss];
}
// 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 = getMid(ss, se);
tree[si] = constructSTUtil(arr, ss, mid, tree, si * 2 + 1)
+ constructSTUtil(arr, mid + 1, se, tree, si * 2 + 2);
return tree[si];
}
/*
* 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)
{
// Allocate memory for segment tree
// Height of segment tree
let x = parseInt(Math.ceil(Math.log(n) / Math.log(2)), 10);
// Maximum size of segment tree
let max_size = 2 * parseInt(Math.pow(2, x), 10) - 1;
// Allocate memory
let tree = new Array(max_size);
tree.fill(0);
// Fill the allocated memory st
constructSTUtil(arr, 0, n - 1, tree, 0);
// Return the constructed segment tree
return tree;
}
/*
* Function to construct lazy array
for segment tree. This function allocates
* memory for lazy array
*/
function constructLazy(arr, n)
{
// Allocate memory for lazy array
// Height of lazy array
let x = parseInt(Math.ceil(Math.log(n) / Math.log(2)), 10);
// Maximum size of lazy array
let max_size = 2 * parseInt(Math.pow(2, x), 10) - 1;
// Allocate memory
let lazy = new Array(max_size);
lazy.fill(0);
// Return the lazy array
return lazy;
}
// Initialize the array to zero
// since all pieces are white
let arr = [0, 0, 0, 0];
let n = arr.length;
// Build segment tree from given array
let tree = constructST(arr, n);
// Allocate memory for Lazy array
let lazy = constructLazy(arr, n);
// Print number of black pieces
// from index 0 to 3
document.write("Black Pieces in given range = " +
getSum(tree, lazy, n, 0, 3) + "</br>");
// UpdateRange: Change color of pieces
// from index 1 to 2
updateRange(tree, lazy, n, 1, 2);
// Print number of black pieces
// from index 0 to 1
document.write("Black Pieces in given range = " +
getSum(tree, lazy, n, 0, 1) + "</br>");
// UpdateRange: Change color of
// pieces from index 0 to 3
updateRange(tree, lazy, n, 0, 3);
// Print number of black pieces
// from index 0 to 3
document.write("Black Pieces in given range = " + getSum(tree, lazy, n, 0, 3));
// This code is contributed by divyeshrabadiy07.
</script>