using System;
using System.Collections.Generic;
class SegmentTree
{
const int MAXSIZE = 1000;
const long INF = long.MaxValue;
static long[] tree = new long[MAXSIZE];
static long[] lazy = new long[MAXSIZE];
// Build our segment tree
static void BuildTree(long[] arr, int arrSize)
{
Stack<(long, long, long)> st = new Stack<(long, long, long)>();
st.Push((1, 0, arrSize - 1));
while (st.Count > 0)
{
(long currNode, long curra, long currb) = st.Pop();
if (curra == INF && currb == INF)
tree[currNode] = tree[currNode * 2] + tree[currNode * 2 + 1];
else if (curra == currb)
tree[currNode] = arr[curra];
else
{
st.Push((currNode, INF, INF));
long mid = (curra + currb) / 2;
st.Push((currNode * 2, curra, mid));
st.Push((currNode * 2 + 1, mid + 1, currb));
}
}
}
// A utility function that propagates
// updates lazily down the tree
static void PushDown(long node, long a, long b)
{
if (lazy[node] != 0)
{
tree[node] += lazy[node] * (b - a + 1);
if (a != b)
{
lazy[2 * node] += lazy[node];
lazy[2 * node + 1] += lazy[node];
}
lazy[node] = 0;
}
}
// Iterative Range_Update function to
// add val to all elements in the
// range i-j (inclusive)
static void UpdateTree(int arrSize, long i, long j, long val)
{
Stack<(long, long, long)> st = new Stack<(long, long, long)>();
st.Push((1, 0, arrSize - 1));
while (st.Count > 0)
{
(long currNode, long curra, long currb) = st.Pop();
if (curra == INF && currb == INF)
tree[currNode] = tree[currNode * 2] + tree[currNode * 2 + 1];
else
{
PushDown(currNode, curra, currb);
if (curra > currb || curra > j || currb < i)
continue;
else if (curra >= i && currb <= j)
{
tree[currNode] += val * (currb - curra + 1);
if (curra != currb)
{
lazy[currNode * 2] += val;
lazy[currNode * 2 + 1] += val;
}
}
else
{
st.Push((currNode, INF, INF));
long mid = (curra + currb) / 2;
st.Push((currNode * 2, curra, mid));
st.Push((currNode * 2 + 1, mid + 1, currb));
}
}
}
}
// A function that finds the sum of
// all elements in the range i-j
static long Query(int arrSize, long i, long j)
{
Stack<(long, long, long)> st = new Stack<(long, long, long)>();
st.Push((1, 0, arrSize - 1));
long result = 0;
while (st.Count > 0)
{
(long currNode, long curra, long currb) = st.Pop();
PushDown(currNode, curra, currb);
if (curra > currb || curra > j || currb < i)
continue;
else if (curra >= i && currb <= j)
result += tree[currNode];
else
{
long mid = (curra + currb) / 2;
st.Push((currNode * 2, curra, mid));
st.Push((currNode * 2 + 1, mid + 1, currb));
}
}
return result;
}
// Driver Code
static void Main()
{
// Initialize our trees with 0
Array.Clear(tree, 0, MAXSIZE);
Array.Clear(lazy, 0, MAXSIZE);
long[] arr = { 1, 3, 5, 7, 9, 11 };
int n = arr.Length;
// Build segment tree from given array
BuildTree(arr, n);
// Print sum of values in array
// from index 1 to 3
Console.WriteLine("Sum of values in given range = " + Query(n, 1, 3));
// Add 10 to all nodes at indexes
// from 1 to 5
UpdateTree(n, 1, 5, 10);
// Find sum after the value is updated
Console.WriteLine("Updated sum of values in given range = " + Query(n, 1, 3));
}
}