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 :



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 :

filter_none

edit
close

play_arrow

link
brightness_4
code

// CPP 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 rigth 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 rigth 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);
  
        // maxum 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 rigth 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 rigth 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);
  
        // maxum 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))));
    }
}
  
// fucntion 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;
}
chevron_right

Output:
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.




Striver(underscore)79 at Codechef and codeforces D

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



Improved By : FelipeNoronha



Article Tags :
Practice Tags :