# Sum and Maximum of elements in array from [L, R] before and after updates

Prerequisite: Segment Trees, Lazy Propagation in Segment Tree. Given an array arr[] of N integers. The task is to do the following operations:

1. Change the value arr[i] to min(arr[i], X) where X is an integer for a given range [L, R].
2. Find the maximum value from index L to R where 0 ? L ? R ? N-1 before and after the update given to the array above.
3. Find the sum of the element from index L to R where 0 ? L ? R ? N-1 before and after the update given to the array above.

Examples:

Input: arr[] = {1, 2, 3, 4, 5}, L = 2, R = 4, X = 3
Output: Maximum in range [2, 4] before update: 5 Sum in range [2, 4] before update: 12 Maximum in range [2, 4] after update: 3 Sum in range [2, 4] after update: 9
Explanation: Before Update: arr[] = {1, 2, 3, 4, 5} The maximum value from [L, R] is 5 Sum in range [L, R] is 3 + 4 + 5 = 12
After Update: arr[] = {1, 2, 3, 3, 3} The maximum value from [L, R] is 3 Sum in range [L, R] is 3 + 3 + 3 = 9

Input: arr[] = {1, 4, 19, 0, 7, 22, 7}, L = 1, R = 5, X = 14
Output: Maximum in range [1, 5] before update: 22 Sum in range [1, 5] before update: 52 Maximum in range [1, 5] after update: 22 Sum in range [1, 5] after update: 39
Explanation: Before Update: arr[] = {1, 4, 19, 0, 7, 22, 7} The maximum value from [L, R] is 22 Sum in range [L, R] is 4 + 19 + 0 + 7 + 22 = 52
After Update: arr[] = {1, 4, 14, 0, 7, 14, 7} The maximum value from [L, R] is 14 Sum in range [L, R] is 4 + 14 + 0 + 7 + 14 = 39

Approach: Few Terms for Lazy Propagation:

1. pushdown(): The lazy tag is applied to current node and then is pushed down to its children.
2. tag_condition: It is the condition that needs to be satisfied to set the lazy node. In normal lazy trees, it is generally the condition that ranges of the node covers lie entirely in the update range.
3. A node in the segment tree represents a range of the array. Now all elements in that range will have different values and they will change by different amounts during an update. So we need the information about distinct values and their counts in that range. So this becomes a worst-case O(N) operation as at max N distinct nodes in a range.
4. Below is the approach to solve these restrictions in Segment Tree. Each node in the Segment Tree will have the following values:
• value: The value of a range, here sum of all elements in that range
• maxval: Maximum value in that range
• secondmax: Strict second maximum value in that range
• cnt_max: Count of maximum value in that range
• cnt_secondmax: Count of secondmax in that range

Below are the steps:

1. Form a Segment Tree for the given array element with every nodes having the properties mentioned above.
2. For updateQuery() call do the following:
• If the max_value is less than the updated value(say X), then no value will be changed as min(arr[i], X) will be arr[i] itself for this case.
• If secondmax ? X ? maxvalue, then update the value of that node and the newSum will be calculated by:
```new_sum = sum - f*maxvalue + f*X,
where f is the frequency of maxvalue```
1. Query for find the maximum number in the range [L, R]:
• If range [L, R] completely lies outside the range, then return 0.
• If range [L, R] completely lies inside the range, then maximum value for the current range is tree[pos].mx1.
• Else check the above condition for left and right subtree recursively.
• The maximum value for all the above recursive call gives the maximum value in the range [L, R].
2. Query for find the sum in the range [L, R]:
• If range [L, R] completely lies outside the range, then return 0.
• If range [L, R] completely lies inside the range, then the sum for the current range is tree[pos].sum.
• Else check the above condition for left and right subtree recursively.
• The sum of all value for above recursive call gives the sum in the range [L, R].

Below is the implementation of the above approach:

## CPP

 `// C++ program for the above approach``#include ``using` `namespace` `std;` `// Node for each Segment Tree``typedef` `struct` `node {` `    ``int` `sum;``    ``int` `mx1;``    ``int` `mx2;``    ``int` `cnt_mx1;``    ``int` `cnt_mx2;` `    ``// Constructor``    ``node()``    ``{``        ``sum = mx1 = mx2 = 0;``        ``cnt_mx1 = cnt_mx2 = 0;``    ``}` `} node;` `const` `int` `N = 1e5 + 5;` `// Segment Tree Node``node tree[N];` `// For Lazy Propagation``int` `lazy[N];` `// Function to merge 2 nodes of Segment``// Tree``void` `combine(``int` `pos)``{` `    ``// Map to store the count of``    ``// maximum1 and maximum2 for every``    ``// node segment tree``    ``map<``int``, ``int``> x;` `    ``// Update the count for left and``    ``// right subtree``    ``x[tree[2 * pos + 1].mx1] += tree[2 * pos + 1].cnt_mx1;``    ``x[tree[2 * pos + 1].mx2] += tree[2 * pos + 1].cnt_mx2;``    ``x[tree[2 * pos + 2].mx1] += tree[2 * pos + 2].cnt_mx1;``    ``x[tree[2 * pos + 2].mx2] += tree[2 * pos + 2].cnt_mx2;` `    ``// Vector pair to store mx1 & mx2``    ``vector > v;` `    ``// Traverse the v``    ``for` `(``auto` `it = x.begin(); it != x.end(); it++) {``        ``v.push_back({ it->first, it->second });``    ``}` `    ``int` `n = v.size();` `    ``// Update the mx1 and mx2 after``    ``// combined node``    ``tree[pos].mx1 = v[n - 1].first;``    ``tree[pos].cnt_mx1 = v[n - 1].second;` `    ``// If only one node``    ``if` `(n == 1) {``        ``tree[pos].mx2 = tree[pos].cnt_mx2 = 0;``    ``}` `    ``// ELse Update mx2 and cnt_mx2``    ``else` `{``        ``tree[pos].mx2 = v[n - 2].first;``        ``tree[pos].cnt_mx2 = v[n - 2].second;``    ``}` `    ``// Update the sum``    ``tree[pos].sum = tree[2 * pos + 1].sum``                    ``+ tree[2 * pos + 2].sum;``}` `// Function that returns true if tag``// condition is satisfied, and we can``// do lazy update``bool` `tag_condition(``int` `pos, ``int` `x)``{``    ``if` `(tree[pos].mx1 > x``        ``&& tree[pos].mx2 <= x) {``        ``return` `true``;``    ``}``    ``return` `false``;``}` `// Function that pushes down the lazy``// value of the current node to its children``void` `pushdown(``int` `beg, ``int` `end, ``int` `pos)``{``    ``// If tag condition satisfies``    ``if` `(tag_condition(pos, lazy[pos])) {` `        ``int` `initsum = tree[pos].mx1 * tree[pos].cnt_mx1;``        ``int` `finsum = lazy[pos] * tree[pos].cnt_mx1;``        ``tree[pos].sum += finsum - initsum;` `        ``// If only one node, then update the``        ``// maximum value to current position``        ``if` `(beg == end)``            ``tree[pos].mx1 = lazy[pos];` `        ``// If lazy[pos] > maximum value``        ``else` `{` `            ``// Update mx1 to current``            ``// lazy[pos]``            ``if` `(lazy[pos] > tree[pos].mx2)``                ``tree[pos].mx1 = lazy[pos];` `            ``// Else update the count``            ``else` `{` `                ``tree[pos].mx1 = lazy[pos];``                ``tree[pos].cnt_mx1 += tree[pos].cnt_mx2;``                ``tree[pos].mx2 = tree[pos].cnt_mx2 = 0;` `                ``// map to store the cnt``                ``// of maximum1 and maximum2``                ``// for every node in segment``                ``// tree``                ``map<``int``, ``int``> x;``                ``x[tree[2 * pos + 1].mx1] += tree[2 * pos + 1].cnt_mx1;``                ``x[tree[2 * pos + 1].mx2] += tree[2 * pos + 1].cnt_mx2;``                ``x[tree[2 * pos + 2].mx1] += tree[2 * pos + 2].cnt_mx1;``                ``x[tree[2 * pos + 2].mx2] += tree[2 * pos + 2].cnt_mx2;` `                ``// Traverse the map``                ``for` `(``auto` `it = x.begin(); it != x.end(); it++) {` `                    ``// Update the maximum``                    ``// count``                    ``if` `(it->first != tree[pos].mx1``                        ``&& it->first > tree[pos].mx2) {``                        ``tree[pos].mx2 = it->first;``                        ``tree[pos].cnt_mx2 = it->second;``                    ``}``                ``}``            ``}` `            ``// Update the value for``            ``// lazy left and right``            ``// subtree``            ``lazy[2 * pos + 1] = min(lazy[2 * pos + 1],``                                    ``lazy[pos]);``            ``lazy[2 * pos + 2] = min(lazy[2 * pos + 2],``                                    ``lazy[pos]);``        ``}``    ``}` `    ``lazy[pos] = INT_MAX;``}` `// Function that Lazy update in segment``// tree i.e., arr[i] = min(arr[i], val)``void` `update(``int` `beg, ``int` `end, ``int` `l, ``int` `r,``            ``int` `pos, ``int` `val)``{` `    ``// Push the current node value to``    ``// left and right subtree``    ``if` `(lazy[pos] < INT_MAX)``        ``pushdown(beg, end, pos);` `    ``// If inside the range, then update``    ``// the value as per the conditions``    ``if` `(l <= beg and r >= end``        ``&& tag_condition(pos, val)) {``        ``lazy[pos] = min(lazy[pos], val);``        ``pushdown(beg, end, pos);``        ``return``;``    ``}` `    ``// Outside the range``    ``else` `if` `(l > end || r < beg``             ``|| beg > end``             ``|| tree[pos].mx1 <= val) {``        ``return``;``    ``}` `    ``// Check for left and right subtree``    ``else` `{` `        ``int` `mid = (beg + end) / 2;``        ``update(beg, mid, l, r,``               ``2 * pos + 1, val);``        ``update(mid + 1, end, l, r,``               ``2 * pos + 2, val);``        ``combine(pos);``    ``}``}` `// Function that returns the maximum``// value in range [L, R]``int` `query1(``int` `beg, ``int` `end, ``int` `l,``           ``int` `r, ``int` `pos)``{` `    ``// Push the current node value in``    ``// the left and right subtree``    ``if` `(lazy[pos] < INT_MAX) {``        ``pushdown(beg, end, pos);``    ``}` `    ``// If inside the range, then return``    ``// the maximum value``    ``if` `(l <= beg && r >= end) {``        ``return` `tree[pos].mx1;``    ``}` `    ``// Outside the range``    ``else` `if` `(l > end || r < beg``             ``|| beg > end) {``        ``return` `0;``    ``}` `    ``// Check for left and right subtree``    ``else` `{``        ``int` `mid = (beg + end) / 2;``        ``return` `max(query1(beg, mid, l, r,``                          ``2 * pos + 1),``                   ``query1(mid + 1, end, l,``                          ``r, 2 * pos + 2));``    ``}``}` `// Function to find the sum in the``// range [L, R]``int` `query2(``int` `beg, ``int` `end, ``int` `l,``           ``int` `r, ``int` `pos)``{``    ``// Push the current node value``    ``if` `(lazy[pos] < INT_MAX)``        ``pushdown(beg, end, pos);` `    ``// If in the range, return the``    ``// sum``    ``if` `(l <= beg and r >= end)``        ``return` `tree[pos].sum;``    ``else` `if` `(l > end || r < beg``             ``|| beg > end) {``        ``return` `0;``    ``}` `    ``// Check for left and right subtree``    ``else` `{``        ``int` `mid = (beg + end) / 2;` `        ``return` `query2(beg, mid, l, r,``                      ``2 * pos + 1)``               ``+ query1(mid + 1, end, l,``                        ``r, 2 * pos + 2);``    ``}``}` `// Construct Segment Tree``void` `constr(``int` `arr[], ``int` `beg,``            ``int` `end, ``int` `pos)``{``    ``// If only a single node``    ``if` `(beg == end) {``        ``int` `x = arr[beg];``        ``tree[pos].sum = x;``        ``tree[pos].mx1 = x;` `        ``tree[pos].cnt_mx1 = 1;``        ``tree[pos].mx2 = 0;``        ``tree[pos].cnt_mx2 = 0;` `        ``return``;``    ``}` `    ``// Recursively update for``    ``// left and right subtree``    ``else` `{` `        ``int` `mid = (beg + end) / 2;` `        ``// For Left subtree``        ``constr(arr, beg, mid, 2 * pos + 1);` `        ``// For right subtree``        ``constr(arr, mid + 1, end, 2 * pos + 2);` `        ``// Combine the two left and``        ``// right subtree``        ``combine(pos);``    ``}``}` `// A utility function to construct``// the segment tree``void` `construct(``int` `arr[], ``int` `n)``{``    ``for` `(``int` `i = 0; i < N; i++) {``        ``lazy[i] = INT_MAX;``    ``}` `    ``// Function call to Construct``    ``// segment tree``    ``constr(arr, 0, n - 1, 0);``}` `// Driver Code``int` `main()``{``    ``int` `arr[] = { 1, 2, 3, 4, 5 };` `    ``// Construct segment tree``    ``construct(arr, 5);` `    ``cout << "Maximum in [2, 4] before update: ";``    ``// Query for maximum in range [0, 4]``    ``cout << query1(0, 4, 2, 4, 0) << endl;` `    ``cout << "Sum in [2, 4] before update: ";``    ``// Query for sum in range [0, 4]``    ``cout << query2(0, 4, 2, 4, 0) << endl;` `    ``// Update Query``    ``update(0, 4, 2, 5, 0, 3);` `    ``cout << endl;``    ``cout << "Updated array elements between "``         ``<< "[2, 4] as min(arr[i], 3)" << endl;``    ``cout << endl;` `    ``cout << "Maximum in [2, 4] after update: ";``    ``// Query for maximum in range [0, 4]``    ``cout << query1(0, 4, 2, 4, 0) << endl;` `    ``cout << "Sum in [2, 4] after update: ";``    ``// Query for maximum in range [0, 4]``    ``cout << query2(0, 4, 2, 4, 0) << endl;` `    ``return` `0;``}`

Output:
```Maximum in [2, 4] before update: 5
Sum in [2, 4] before update: 8

Updated array elements between [2, 4] as min(arr[i], 3)

Maximum in [2, 4] after update: 3
Sum in [2, 4] after update: 6```

Time Complexity: O(N*log N)
Auxiliary Space: O(N)

Previous
Next