Range query for Largest Sum Contiguous Subarray
Given a number N, and Q queries of two types 1 and 2. Task is to write a code for the given query where, in type-1, given l and r, and task is to print the Largest sum Contiguous Subarray and for type 2, given type, index, and value, update value to Aindex.
Examples :
Input : a = {-2, -3, 4, -1, -2, 1, 5, -3} 1st query : 1 5 8 2nd query : 2 1 10 3rd query : 1 1 3 Output : Answer to 1st query : 6 Answer to 3rd query : 11
Explanation : In the first query, task is to print the largest sum of a contiguous subarray in range 5-8, which consists of {-2, 1, 5, -3}. The largest sum is 6, which is formed by the subarray {1, 5}. In the second query, an update operation is done, which updates a[1] to 10, hence the sequence is {10, -3, 4, -1, -2, 1, 5, -3}. In the third query, task is to print the largest sum of a contiguous subarray in range 1-3, which consists of {10, -3, 4}. The largest sum is 11, which is formed by the subarray {10, -3, 4}.
A naive approach is to use Kadane’s algorithm for every type-1 query. The complexity of every type-1 query is O(n). The type-2 query is done in O(1).
Efficient Approach :
An efficient approach is to build a segment tree where each node stores four values(sum, prefixsum, suffixsum, maxsum), and do a range query on it to find the answer to every query. The nodes of segment tree store the four values as mentioned above. The parent will store the merging of left and right child. The parent node stores the value as mentioned below :
parent.sum = left.sum + right.sum
parent.prefixsum = max(left.prefixsum, left.sum + right.prefixsum)
parent.suffixsum = max(right.suffixsum, right.sum + left.suffixsum)
parent.maxsum = max(parent.prefixsum, parent.suffixsum, left.maxsum, right.maxsum, left.suffixsum + right.prefixsum)
Parent node stores the following :
- Parent node’s sum is the summation of left and right child sum.
- Parent node’s prefix sum will be equivalent to maximum of left child’s prefix sum or left child sum + right child prefix sum.
- Parent node’s suffix sum will be equal to right child suffix sum or right child sum + suffix sum of left child
- Parent node’s maxsum will be the maximum of prefixsum or suffix sum of parent or the left or right child’s maxsum or the summation of suffixsum of left child and prefixsum of right child.
Representation of Segment trees :
1. Leaf Nodes are the elements of the input array.
2. Each internal node represents some merging of the leaf nodes. The merging may be different for different problems. For this problem, merging is done as given above.
An array representation of tree is used to represent Segment Trees. For each node at index i, the left child is at index 2 * i + 1, right child at 2 * i + 2 and the parent is at (i – 1) / 2.
Construction of Segment Tree from given array :
Start with a segment arr[0 . . . n-1]. and every time divide the current segment into two halves(if it has not yet become a segment of length 1), and then call the same procedure on both halves, and for each such segment, store the values in all the four variables as given in the formulae above.
Update a given value in array and segment Tree :
Start with the complete segment of the array provided to us. Every time divide the array into two halves, ignore the half in which the index to be updated is not present. Keep on ignoring halves at every step until reach the leaf node, where update the value to the given index. Now, merge the updated values according to the given formulae to all the nodes that are present in the path we have traversed.
Answering a query:
For every query, move to the left and right halves of the tree. Whenever the given range completely overlaps any halve of a tree, return the Node from that half without traversing further in that region. When a halve of the tree completely lies outside the given range, return INT_MIN. On partial overlapping of range, traverse in left and right halves and return accordingly.
Below is the implementation of the above idea :
C++
// C++ program to find Largest Sum Contiguous // Subarray in a given range with updates #include <bits/stdc++.h> using namespace std; // Structure to store // 4 values that are to be stored // in the nodes struct node { int sum, prefixsum, suffixsum, maxsum; }; // array to store the segment tree node tree[4 * 100]; // function to build the tree void build( int arr[], int low, int high, int index) { // the leaf node if (low == high) { tree[index].sum = arr[low]; tree[index].prefixsum = arr[low]; tree[index].suffixsum = arr[low]; tree[index].maxsum = arr[low]; } else { int mid = (low + high) / 2; // left subtree build(arr, low, mid, 2 * index + 1); // right subtree build(arr, mid + 1, high, 2 * index + 2); // parent node's sum is the summation // of left and right child tree[index].sum = tree[2 * index + 1].sum + tree[2 * index + 2].sum; // parent node's prefix sum will be equivalent // to maximum of left child's prefix sum or left // child sum + right child prefix sum. tree[index].prefixsum = max(tree[2 * index + 1].prefixsum, tree[2 * index + 1].sum + tree[2 * index + 2].prefixsum); // parent node's suffix sum will be equal to right // child suffix sum or right child sum + suffix // sum of left child tree[index].suffixsum = max(tree[2 * index + 2].suffixsum, tree[2 * index + 2].sum + tree[2 * index + 1].suffixsum); // maximum will be the maximum of prefix, suffix of // parent or maximum of left child or right child // and summation of left child's suffix and right // child's prefix. tree[index].maxsum = max(tree[index].prefixsum, max(tree[index].suffixsum, max(tree[2 * index + 1].maxsum, max(tree[2 * index + 2].maxsum, tree[2 * index + 1].suffixsum + tree[2 * index + 2].prefixsum)))); } } // function to update the tree void update( int arr[], int index, int low, int high, int idx, int value) { // the node to be updated if (low == high) { tree[index].sum = value; tree[index].prefixsum = value; tree[index].suffixsum = value; tree[index].maxsum = value; } else { int mid = (low + high) / 2; // if node to be updated is in left subtree if (idx <= mid) update(arr, 2 * index + 1, low, mid, idx, value); // if node to be updated is in right subtree else update(arr, 2 * index + 2, mid + 1, high, idx, value); // parent node's sum is the summation of left // and right child tree[index].sum = tree[2 * index + 1].sum + tree[2 * index + 2].sum; // parent node's prefix sum will be equivalent // to maximum of left child's prefix sum or left // child sum + right child prefix sum. tree[index].prefixsum = max(tree[2 * index + 1].prefixsum, tree[2 * index + 1].sum + tree[2 * index + 2].prefixsum); // parent node's suffix sum will be equal to right // child suffix sum or right child sum + suffix // sum of left child tree[index].suffixsum = max(tree[2 * index + 2].suffixsum, tree[2 * index + 2].sum + tree[2 * index + 1].suffixsum); // maximum will be the maximum of prefix, suffix of // parent or maximum of left child or right child // and summation of left child's suffix and // right child's prefix. tree[index].maxsum = max(tree[index].prefixsum, max(tree[index].suffixsum, max(tree[2 * index + 1].maxsum, max(tree[2 * index + 2].maxsum, tree[2 * index + 1].suffixsum + tree[2 * index + 2].prefixsum)))); } } // function to return answer to every type-1 query node query( int arr[], int index, int low, int high, int l, int r) { // initially all the values are INT_MIN node result; result.sum = result.prefixsum = result.suffixsum = result.maxsum = INT_MIN; // range does not lies in this subtree if (r < low || high < l) return result; // complete overlap of range if (l <= low && high <= r) return tree[index]; int mid = (low + high) / 2; // right subtree if (l > mid) return query(arr, 2 * index + 2, mid + 1, high, l, r); // left subtree if (r <= mid) return query(arr, 2 * index + 1, low, mid, l, r); node left = query(arr, 2 * index + 1, low, mid, l, r); node right = query(arr, 2 * index + 2, mid + 1, high, l, r); // finding the maximum and returning it result.sum = left.sum + right.sum; result.prefixsum = max(left.prefixsum, left.sum + right.prefixsum); result.suffixsum = max(right.suffixsum, right.sum + left.suffixsum); result.maxsum = max(result.prefixsum, max(result.suffixsum, max(left.maxsum, max(right.maxsum, left.suffixsum + right.prefixsum)))); return result; } // Driver Code int main() { int a[] = { -2, -3, 4, -1, -2, 1, 5, -3 }; int n = sizeof (a) / sizeof (a[0]); // build the tree build(a, 0, n - 1, 0); // 1st query type-1 int l = 5, r = 8; cout << query(a, 0, 0, n - 1, l - 1, r - 1).maxsum; cout << endl; // 2nd type-2 query int index = 1; int value = 10; a[index - 1] = value; update(a, 0, 0, n - 1, index - 1, value); // 3rd type-1 query l = 1, r = 3; cout << query(a, 0, 0, n - 1, l - 1, r - 1).maxsum; return 0; } |
Java
// Java program to find Largest Sum Contiguous // Subarray in a given range with updates class GFG { // Structure to store 4 values that are // to be stored in the nodes static class node { int sum, prefixsum, suffixsum, maxsum; }; // array to store the segment tree static node[] tree = new node[ 4 * 100 ]; // function to build the tree static void build( int arr[], int low, int high, int index) { // the leaf node if (low == high) { tree[index].sum = arr[low]; tree[index].prefixsum = arr[low]; tree[index].suffixsum = arr[low]; tree[index].maxsum = arr[low]; } else { int mid = (low + high) / 2 ; // left subtree build(arr, low, mid, 2 * index + 1 ); // right subtree build(arr, mid + 1 , high, 2 * index + 2 ); // parent node's sum is the summation // of left and right child tree[index].sum = tree[ 2 * index + 1 ].sum + tree[ 2 * index + 2 ].sum; // parent node's prefix sum will be equivalent // to maximum of left child's prefix sum or left // child sum + right child prefix sum. tree[index].prefixsum = Math.max(tree[ 2 * index + 1 ].prefixsum, tree[ 2 * index + 1 ].sum + tree[ 2 * index + 2 ].prefixsum); // parent node's suffix sum will be equal to right // child suffix sum or right child sum + suffix // sum of left child tree[index].suffixsum = Math.max(tree[ 2 * index + 2 ].suffixsum, tree[ 2 * index + 2 ].sum + tree[ 2 * index + 1 ].suffixsum); // maximum will be the maximum of prefix, suffix of // parent or maximum of left child or right child // and summation of left child's suffix and right // child's prefix. tree[index].maxsum = Math.max(tree[index].prefixsum, Math.max(tree[index].suffixsum, Math.max(tree[ 2 * index + 1 ].maxsum, Math.max(tree[ 2 * index + 2 ].maxsum, tree[ 2 * index + 1 ].suffixsum + tree[ 2 * index + 2 ].prefixsum)))); } } // function to update the tree static void update( int arr[], int index, int low, int high, int idx, int value) { // the node to be updated if (low == high) { tree[index].sum = value; tree[index].prefixsum = value; tree[index].suffixsum = value; tree[index].maxsum = value; } else { int mid = (low + high) / 2 ; // if node to be updated is in left subtree if (idx <= mid) { update(arr, 2 * index + 1 , low, mid, idx, value); } // if node to be updated is in right subtree else { update(arr, 2 * index + 2 , mid + 1 , high, idx, value); } // parent node's sum is the summation of left // and right child tree[index].sum = tree[ 2 * index + 1 ].sum + tree[ 2 * index + 2 ].sum; // parent node's prefix sum will be equivalent // to maximum of left child's prefix sum or left // child sum + right child prefix sum. tree[index].prefixsum = Math.max(tree[ 2 * index + 1 ].prefixsum, tree[ 2 * index + 1 ].sum + tree[ 2 * index + 2 ].prefixsum); // parent node's suffix sum will be equal to right // child suffix sum or right child sum + suffix // sum of left child tree[index].suffixsum = Math.max(tree[ 2 * index + 2 ].suffixsum, tree[ 2 * index + 2 ].sum + tree[ 2 * index + 1 ].suffixsum); // maximum will be the maximum of prefix, suffix of // parent or maximum of left child or right child // and summation of left child's suffix and // right child's prefix. tree[index].maxsum = Math.max(tree[index].prefixsum, Math.max(tree[index].suffixsum, Math.max(tree[ 2 * index + 1 ].maxsum, Math.max(tree[ 2 * index + 2 ].maxsum, tree[ 2 * index + 1 ].suffixsum + tree[ 2 * index + 2 ].prefixsum)))); } } // function to return answer to every type-1 query static node query( int arr[], int index, int low, int high, int l, int r) { // initially all the values are Integer.MIN_VALUE node result = new node(); result.sum = result.prefixsum = result.suffixsum = result.maxsum = Integer.MIN_VALUE; // range does not lies in this subtree if (r < low || high < l) { return result; } // complete overlap of range if (l <= low && high <= r) { return tree[index]; } int mid = (low + high) / 2 ; // right subtree if (l > mid) { return query(arr, 2 * index + 2 , mid + 1 , high, l, r); } // left subtree if (r <= mid) { return query(arr, 2 * index + 1 , low, mid, l, r); } node left = query(arr, 2 * index + 1 , low, mid, l, r); node right = query(arr, 2 * index + 2 , mid + 1 , high, l, r); // finding the maximum and returning it result.sum = left.sum + right.sum; result.prefixsum = Math.max(left.prefixsum, left.sum + right.prefixsum); result.suffixsum = Math.max(right.suffixsum, right.sum + left.suffixsum); result.maxsum = Math.max(result.prefixsum, Math.max(result.suffixsum, Math.max(left.maxsum, Math.max(right.maxsum, left.suffixsum + right.prefixsum)))); return result; } // Driver Code public static void main(String[] args) { int a[] = {- 2 , - 3 , 4 , - 1 , - 2 , 1 , 5 , - 3 }; int n = a.length; for ( int i = 0 ; i < 4 * 100 ; i++) { tree[i] = new node(); } // build the tree build(a, 0 , n - 1 , 0 ); // 1st query type-1 int l = 5 , r = 8 ; System.out.print(query(a, 0 , 0 , n - 1 , l - 1 , r - 1 ).maxsum); System.out.println(); // 2nd type-2 query int index = 1 ; int value = 10 ; a[index - 1 ] = value; update(a, 0 , 0 , n - 1 , index - 1 , value); // 3rd type-1 query l = 1 ; r = 3 ; System.out.print(query(a, 0 , 0 , n - 1 , l - 1 , r - 1 ).maxsum); } } // This code is contributed by 29AjayKumar |
Python3
# Python program to find Largest Sum Contiguous # Subarray in a given range with updates from sys import maxsize INT_MIN = - maxsize # Structure to store # 4 values that are to be stored # in the nodes class node: def __init__( self ): self . sum = 0 self .prefixsum = 0 self .suffixsum = 0 self .maxsum = 0 # array to store the segment tree tree = [ 0 ] * ( 4 * 100 ) for i in range ( 4 * 100 ): tree[i] = node() def build(arr: list , low: int , high: int , index: int ): global tree # the leaf node if low = = high: tree[index]. sum = arr[low] tree[index].prefixsum = arr[low] tree[index].suffixsum = arr[low] tree[index].maxsum = arr[low] else : mid = (low + high) >> 1 # left subtree build(arr, low, mid, 2 * index + 1 ) # right subtree build(arr, mid + 1 , high, 2 * index + 2 ) # parent node's sum is the summation # of left and right child tree[index]. sum = tree[ 2 * index + 1 ]. sum + \ tree[ 2 * index + 2 ]. sum # parent node's prefix sum will be equivalent # to maximum of left child's prefix sum or left # child sum + right child prefix sum. tree[index].prefixsum = max ( tree[ 2 * index + 1 ].prefixsum, tree[ 2 * index + 1 ]. sum + tree[ 2 * index + 2 ].prefixsum) # parent node's suffix sum will be equal to right # child suffix sum or right child sum + suffix # sum of left child tree[index].suffixsum = max ( tree[ 2 * index + 2 ].suffixsum, tree[ 2 * index + 2 ]. sum + tree[ 2 * index + 1 ].suffixsum) # maximum will be the maximum of prefix, suffix of # parent or maximum of left child or right child # and summation of left child's suffix and right # child's prefix. tree[index].maxsum = max (tree[index].prefixsum, max (tree[index].suffixsum, max (tree[ 2 * index + 1 ].maxsum, max (tree[ 2 * index + 2 ].maxsum, tree[ 2 * index + 1 ].suffixsum + tree[ 2 * index + 2 ].prefixsum)))) # function to update the tree def update(arr: list , index: int , low: int , high: int , idx: int , value: int ): global tree # the node to be updated if low = = high: tree[index]. sum = value tree[index].prefixsum = value tree[index].suffixsum = value tree[index].maxsum = value else : mid = (low + high) >> 1 # if node to be updated is in left subtree if idx < = mid: update(arr, 2 * index + 1 , low, mid, idx, value) # if node to be updated is in right subtree else : update(arr, 2 * index + 2 , mid + 1 , high, idx, value) # parent node's sum is the summation of left # and right child tree[index]. sum = tree[ 2 * index + 1 ]. sum + \ tree[ 2 * index + 2 ]. sum # parent node's prefix sum will be equivalent # to maximum of left child's prefix sum or left # child sum + right child prefix sum. tree[index].prefixsum = max (tree[ 2 * index + 1 ].prefixsum, tree[ 2 * index + 1 ]. sum + tree[ 2 * index + 2 ].prefixsum) # parent node's suffix sum will be equal to right # child suffix sum or right child sum + suffix # sum of left child tree[index].suffixsum = max (tree[ 2 * index + 2 ].suffixsum, tree[ 2 * index + 2 ]. sum + tree[ 2 * index + 1 ].suffixsum) # maximum will be the maximum of prefix, suffix of # parent or maximum of left child or right child # and summation of left child's suffix and # right child's prefix. tree[index].maxsum = max (tree[index].prefixsum, max (tree[index].suffixsum, max (tree[ 2 * index + 1 ].maxsum, max (tree[ 2 * index + 2 ].maxsum, tree[ 2 * index + 1 ].suffixsum + tree[ 2 * index + 2 ].prefixsum)))) # function to return answer to every type-1 query def query(arr: list , index: int , low: int , high: int , l: int , r: int ) - > node: # initially all the values are INT_MIN result = node() result. sum = result.prefixsum = result.\ suffixsum = result.maxsum = INT_MIN # range does not lies in this subtree if r < low or high < l: return result # complete overlap of range if l < = low and high < = r: return tree[index] mid = (low + high) >> 1 # right subtree if l > mid: return query(arr, 2 * index + 2 , mid + 1 , high, l, r) # left subtree if r < = mid: return query(arr, 2 * index + 1 , low, mid, l, r) left = query(arr, 2 * index + 1 , low, mid, l, r) right = query(arr, 2 * index + 2 , mid + 1 , high, l, r) # finding the maximum and returning it result. sum = left. sum + right. sum result.prefixsum = max (left.prefixsum, left. sum + right.prefixsum) result.suffixsum = max (right.suffixsum, right. sum + left.suffixsum) result.maxsum = max (result.prefixsum, max (result.suffixsum, max (left.maxsum, max (right.maxsum, left.suffixsum + right.prefixsum)))) return result # Driver Code if __name__ = = "__main__" : a = [ - 2 , - 3 , 4 , - 1 , - 2 , 1 , 5 , - 3 ] n = len (a) # build the tree build(a, 0 , n - 1 , 0 ) # 1st query type-1 l = 5 r = 8 print (query(a, 0 , 0 , n - 1 , l - 1 , r - 1 ).maxsum) # 2nd type-2 query index = 1 value = 10 a[index - 1 ] = value update(a, 0 , 0 , n - 1 , index - 1 , value) # 3rd type-1 query l = 1 r = 3 print (query(a, 0 , 0 , n - 1 , l - 1 , r - 1 ).maxsum) # This code is contributed by # sanjeev2552 |
C#
// C# program to find Largest Sum Contiguous // Subarray in a given range with updates using System; using System.Collections.Generic; class GFG { // Structure to store 4 values that are // to be stored in the nodes public class node { public int sum, prefixsum, suffixsum, maxsum; }; // array to store the segment tree static node[] tree = new node[4 * 100]; // function to build the tree static void build( int []arr, int low, int high, int index) { // the leaf node if (low == high) { tree[index].sum = arr[low]; tree[index].prefixsum = arr[low]; tree[index].suffixsum = arr[low]; tree[index].maxsum = arr[low]; } else { int mid = (low + high) / 2; // left subtree build(arr, low, mid, 2 * index + 1); // right subtree build(arr, mid + 1, high, 2 * index + 2); // parent node's sum is the summation // of left and right child tree[index].sum = tree[2 * index + 1].sum + tree[2 * index + 2].sum; // parent node's prefix sum will be equivalent // to maximum of left child's prefix sum or left // child sum + right child prefix sum. tree[index].prefixsum = Math.Max(tree[2 * index + 1].prefixsum, tree[2 * index + 1].sum + tree[2 * index + 2].prefixsum); // parent node's suffix sum will be equal to right // child suffix sum or right child sum + suffix // sum of left child tree[index].suffixsum = Math.Max(tree[2 * index + 2].suffixsum, tree[2 * index + 2].sum + tree[2 * index + 1].suffixsum); // maximum will be the maximum of prefix, suffix of // parent or maximum of left child or right child // and summation of left child's suffix and right // child's prefix. tree[index].maxsum = Math.Max(tree[index].prefixsum, Math.Max(tree[index].suffixsum, Math.Max(tree[2 * index + 1].maxsum, Math.Max(tree[2 * index + 2].maxsum, tree[2 * index + 1].suffixsum + tree[2 * index + 2].prefixsum)))); } } // function to update the tree static void update( int []arr, int index, int low, int high, int idx, int value) { // the node to be updated if (low == high) { tree[index].sum = value; tree[index].prefixsum = value; tree[index].suffixsum = value; tree[index].maxsum = value; } else { int mid = (low + high) / 2; // if node to be updated is in left subtree if (idx <= mid) { update(arr, 2 * index + 1, low, mid, idx, value); } // if node to be updated is in right subtree else { update(arr, 2 * index + 2, mid + 1, high, idx, value); } // parent node's sum is the summation of left // and right child tree[index].sum = tree[2 * index + 1].sum + tree[2 * index + 2].sum; // parent node's prefix sum will be equivalent // to maximum of left child's prefix sum or left // child sum + right child prefix sum. tree[index].prefixsum = Math.Max(tree[2 * index + 1].prefixsum, tree[2 * index + 1].sum + tree[2 * index + 2].prefixsum); // parent node's suffix sum will be equal to right // child suffix sum or right child sum + suffix // sum of left child tree[index].suffixsum = Math.Max(tree[2 * index + 2].suffixsum, tree[2 * index + 2].sum + tree[2 * index + 1].suffixsum); // maximum will be the maximum of prefix, suffix of // parent or maximum of left child or right child // and summation of left child's suffix and // right child's prefix. tree[index].maxsum = Math.Max(tree[index].prefixsum, Math.Max(tree[index].suffixsum, Math.Max(tree[2 * index + 1].maxsum, Math.Max(tree[2 * index + 2].maxsum, tree[2 * index + 1].suffixsum + tree[2 * index + 2].prefixsum)))); } } // function to return answer to every type-1 query static node query( int []arr, int index, int low, int high, int l, int r) { // initially all the values are int.MinValue node result = new node(); result.sum = result.prefixsum = result.suffixsum = result.maxsum = int .MinValue; // range does not lies in this subtree if (r < low || high < l) { return result; } // complete overlap of range if (l <= low && high <= r) { return tree[index]; } int mid = (low + high) / 2; // right subtree if (l > mid) { return query(arr, 2 * index + 2, mid + 1, high, l, r); } // left subtree if (r <= mid) { return query(arr, 2 * index + 1, low, mid, l, r); } node left = query(arr, 2 * index + 1, low, mid, l, r); node right = query(arr, 2 * index + 2, mid + 1, high, l, r); // finding the maximum and returning it result.sum = left.sum + right.sum; result.prefixsum = Math.Max(left.prefixsum, left.sum + right.prefixsum); result.suffixsum = Math.Max(right.suffixsum, right.sum + left.suffixsum); result.maxsum = Math.Max(result.prefixsum, Math.Max(result.suffixsum, Math.Max(left.maxsum, Math.Max(right.maxsum, left.suffixsum + right.prefixsum)))); return result; } // Driver Code public static void Main(String[] args) { int []a = {-2, -3, 4, -1, -2, 1, 5, -3}; int n = a.Length; for ( int i = 0; i < 4 * 100; i++) { tree[i] = new node(); } // build the tree build(a, 0, n - 1, 0); // 1st query type-1 int l = 5, r = 8; Console.Write(query(a, 0, 0, n - 1, l - 1, r - 1).maxsum); Console.WriteLine(); // 2nd type-2 query int index = 1; int value = 10; a[index - 1] = value; update(a, 0, 0, n - 1, index - 1, value); // 3rd type-1 query l = 1; r = 3; Console.Write(query(a, 0, 0, n - 1, l - 1, r - 1).maxsum); } } // This code is contributed by Rajput-Ji |
Javascript
<script> // Javascript program to find Largest Sum // Contiguous Subarray in a given range // with updates // Structure to store 4 values that are // to be stored in the nodes class node { constructor() { this .sum = 0; this .prefixsum = 0; this .suffixsum = 0; this .maxsum = 0; } }; // Array to store the segment tree var tree = Array(4 * 100).fill( new node()); // Function to build the tree function build(arr, low, high, index) { // The leaf node if (low == high) { tree[index].sum = arr[low]; tree[index].prefixsum = arr[low]; tree[index].suffixsum = arr[low]; tree[index].maxsum = arr[low]; } else { var mid = parseInt((low + high) / 2); // Left subtree build(arr, low, mid, 2 * index + 1); // Right subtree build(arr, mid + 1, high, 2 * index + 2); // Parent node's sum is the summation // of left and right child tree[index].sum = tree[2 * index + 1].sum + tree[2 * index + 2].sum; // Parent node's prefix sum will be equivalent // to maximum of left child's prefix sum or left // child sum + right child prefix sum. tree[index].prefixsum = Math.max(tree[2 * index + 1].prefixsum, tree[2 * index + 1].sum + tree[2 * index + 2].prefixsum); // Parent node's suffix sum will be equal to right // child suffix sum or right child sum + suffix // sum of left child tree[index].suffixsum = Math.max(tree[2 * index + 2].suffixsum, tree[2 * index + 2].sum + tree[2 * index + 1].suffixsum); // maximum will be the maximum of prefix, suffix of // parent or maximum of left child or right child // and summation of left child's suffix and right // child's prefix. tree[index].maxsum = Math.max(tree[index].prefixsum, Math.max(tree[index].suffixsum, Math.max(tree[2 * index + 1].maxsum, Math.max(tree[2 * index + 2].maxsum, tree[2 * index + 1].suffixsum + tree[2 * index + 2].prefixsum)))); } } // Function to update the tree function update(arr, index, low, high, idx, value) { // The node to be updated if (low == high) { tree[index].sum = value; tree[index].prefixsum = value; tree[index].suffixsum = value; tree[index].maxsum = value; } else { var mid = parseInt((low + high) / 2); // If node to be updated is in left subtree if (idx <= mid) { update(arr, 2 * index + 1, low, mid, idx, value); } // If node to be updated is in right subtree else { update(arr, 2 * index + 2, mid + 1, high, idx, value); } // Parent node's sum is the summation of left // and right child tree[index].sum = tree[2 * index + 1].sum + tree[2 * index + 2].sum; // Parent node's prefix sum will be equivalent // to maximum of left child's prefix sum or left // child sum + right child prefix sum. tree[index].prefixsum = Math.max(tree[2 * index + 1].prefixsum, tree[2 * index + 1].sum + tree[2 * index + 2].prefixsum); // Parent node's suffix sum will be equal to right // child suffix sum or right child sum + suffix // sum of left child tree[index].suffixsum = Math.max(tree[2 * index + 2].suffixsum, tree[2 * index + 2].sum + tree[2 * index + 1].suffixsum); // maximum will be the maximum of prefix, suffix of // parent or maximum of left child or right child // and summation of left child's suffix and // right child's prefix. tree[index].maxsum = Math.max(tree[index].prefixsum, Math.max(tree[index].suffixsum, Math.max(tree[2 * index + 1].maxsum, Math.max(tree[2 * index + 2].maxsum, tree[2 * index + 1].suffixsum + tree[2 * index + 2].prefixsum)))); } } // Function to return answer to every type-1 query function query(arr, index, low, high, l, r) { // Initially all the values are int.MinValue var result = new node(); result.sum = result.prefixsum = result.suffixsum = result.maxsum = -1000000000; // Range does not lies in this subtree if (r < low || high < l) { return result; } // Complete overlap of range if (l <= low && high <= r) { return tree[index]; } var mid = parseInt((low + high) / 2); // Right subtree if (l > mid) { return query(arr, 2 * index + 2, mid + 1, high, l, r); } // Left subtree if (r <= mid) { return query(arr, 2 * index + 1, low, mid, l, r); } var left = query(arr, 2 * index + 1, low, mid, l, r); var right = query(arr, 2 * index + 2, mid + 1, high, l, r); // Finding the maximum and returning it result.sum = left.sum + right.sum; result.prefixsum = Math.max(left.prefixsum, left.sum + right.prefixsum); result.suffixsum = Math.max(right.suffixsum, right.sum + left.suffixsum); result.maxsum = Math.max(result.prefixsum, Math.max(result.suffixsum, Math.max(left.maxsum, Math.max(right.maxsum, left.suffixsum + right.prefixsum)))); return result; } // Driver Code var a = [ -2, -3, 4, -1, -2, 1, 5, -3 ]; var n = a.length; for ( var i = 0; i < 4 * 100; i++) { tree[i] = new node(); } // Build the tree build(a, 0, n - 1, 0); // 1st query type-1 var l = 5, r = 8; document.write(query(a, 0, 0, n - 1, l - 1, r - 1).maxsum); document.write( "<br>" ); // 2nd type-2 query var index = 1; var value = 10; a[index - 1] = value; update(a, 0, 0, n - 1, index - 1, value); // 3rd type-1 query l = 1; r = 3; document.write(query(a, 0, 0, n - 1, l - 1, r - 1).maxsum); // This code is contributed by rrrtnx </script> |
6 11
Time Complexity: O(n log n) for building the tree, O(log n) for every type-1 query, O(1) for type-2 query.