Open In App

Maximum prefix-sum for a given range

Last Updated : 24 Mar, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given an array arr[] of integers and a list of queries. Each query consists of two indices, leftIndex and rightIndex, defining a range in the array. For each query, calculate the maximum prefix sum within the given range.
Note: A prefix sum is the sum of all elements from the start of the range up to a certain point within the range.

Examples:

Input: arr[] = [ -1, 2, 3, -5 ]
leftIndex[] = [ 0, 1 ], rightIndex = [ 3, 3 ]
Output: 4 5
Explanation: For the range [0, 3], the prefix sums are [-1, 1, 4, -1]. The maximum is 4. For the range [1, 3], the prefix sums are [2, 5, 0]. The maximum is 5.

Input: arr = [1, -2, 3, 4, -5], leftIndex = [0, 2, 1], rightIndex = [4, 3, 3]
Output: 6 7 5
Explanation: For the range [0, 4], the prefix sums are [1, -1, 2, 6, 1]. The maximum is 6. For the range [2, 3], the prefix sums are [3, 7]. The maximum is 7. For the range [1, 3], the prefix sums are [-2, 1, 5]. The maximum is 5.

[Naive Approach] – Generating All Subarrays – O(q * n) Time and O(1) Space

The idea is to run a loop from l to r and calculate max prefix sum from l to r for every query.

C++
#include <bits/stdc++.h>
using namespace std;

// Function to return the maximum prefix sum for each query
vector<int> maxPrefixes(vector<int>& arr, 
    vector<int>& leftIndex, vector<int>& rightIndex) {
    int q = leftIndex.size();
    
    // to store the results
    vector<int> res;

    // process all the queries
    for(int i = 0; i < q; i++) {
        int l = leftIndex[i];
        int r = rightIndex[i];

        // to store the sum of prefix arrays
        int sum = 0;

        // to store the max sum
        int maxSum = INT_MIN;

        for (int i = l; i <= r; i++) {
            sum += arr[i];
            maxSum = max(maxSum, sum);
        }
        res.push_back(maxSum);
    }

    return res;
}

int main() {
    vector<int> arr = {1, -2, 3, 4, -5};
    vector<int> leftIndex = {0, 2, 1};
    vector<int> rightIndex = {4, 3, 3};
    vector<int> res = maxPrefixes(arr, leftIndex, rightIndex);
    for(int i = 0; i < res.size(); i++) {
        cout << res[i] << " ";
    }
    return 0;
}
Java
import java.util.*;

class GfG {

    // Function to return the maximum prefix sum for each query
    static List<Integer> maxPrefixes(List<Integer> arr, List<Integer> leftIndex, List<Integer> rightIndex) {
        int q = leftIndex.size();
        
        // to store the results
        List<Integer> res = new ArrayList<>();
        
        // process all the queries
        for (int i = 0; i < q; i++) {
            int l = leftIndex.get(i);
            int r = rightIndex.get(i);
            
            // to store the sum of prefix arrays
            int sum = 0;
            
            // to store the max sum
            int maxSum = Integer.MIN_VALUE;
            
            for (int j = l; j <= r; j++) {
                sum += arr.get(j);
                maxSum = Math.max(maxSum, sum);
            }
            res.add(maxSum);
        }
        
        return res;
    }
    
    public static void main(String[] args) {
        List<Integer> arr = Arrays.asList(1, -2, 3, 4, -5);
        List<Integer> leftIndex = Arrays.asList(0, 2, 1);
        List<Integer> rightIndex = Arrays.asList(4, 3, 3);
        List<Integer> res = maxPrefixes(arr, leftIndex, rightIndex);
        for (int i = 0; i < res.size(); i++) {
            System.out.print(res.get(i) + " ");
        }
    }
}
Python
# Function to return the maximum prefix sum for each query.
def maxPrefixes(arr, leftIndex, rightIndex):
    q = len(leftIndex)
    
    # to store the results
    res = []
    
    # process all the queries
    for i in range(q):
        l = leftIndex[i]
        r = rightIndex[i]
        
        # to store the sum of prefix arrays
        sum_val = 0
        
        # to store the max sum
        maxSum = -float('inf')
        
        for j in range(l, r + 1):
            sum_val += arr[j]
            maxSum = max(maxSum, sum_val)
        res.append(maxSum)
    
    return res

arr = [1, -2, 3, 4, -5]
leftIndex = [0, 2, 1]
rightIndex = [4, 3, 3]
res = maxPrefixes(arr, leftIndex, rightIndex)
print(" ".join(map(str, res)))
C#
using System;
using System.Collections.Generic;

class GfG {

    // Function to return the maximum prefix sum for each query
    static List<int> maxPrefixes(List<int> arr, List<int> leftIndex, List<int> rightIndex) {
        int q = leftIndex.Count;
        
        // to store the results
        List<int> res = new List<int>();
        
        // process all the queries
        for (int i = 0; i < q; i++) {
            int l = leftIndex[i];
            int r = rightIndex[i];
            
            // to store the sum of prefix arrays
            int sum = 0;
            
            // to store the max sum
            int maxSum = int.MinValue;
            
            for (int j = l; j <= r; j++) {
                sum += arr[j];
                maxSum = Math.Max(maxSum, sum);
            }
            res.Add(maxSum);
        }
        
        return res;
    }

    public static void Main() {
        List<int> arr = new List<int> {1, -2, 3, 4, -5};
        List<int> leftIndex = new List<int> {0, 2, 1};
        List<int> rightIndex = new List<int> {4, 3, 3};
        List<int> res = maxPrefixes(arr, leftIndex, rightIndex);
        for (int i = 0; i < res.Count; i++) {
            Console.Write(res[i] + " ");
        }
    }
}
JavaScript
// Function to return the maximum prefix sum for each query.
function maxPrefixes(arr, leftIndex, rightIndex) {
    let q = leftIndex.length;
    
    // to store the results
    let res = [];
    
    // process all the queries
    for (let i = 0; i < q; i++) {
        let l = leftIndex[i];
        let r = rightIndex[i];
        
        // to store the sum of prefix arrays
        let sum = 0;
        
        // to store the max sum
        let maxSum = -Infinity;
        
        for (let j = l; j <= r; j++) {
            sum += arr[j];
            maxSum = Math.max(maxSum, sum);
        }
        res.push(maxSum);
    }
    
    return res;
}

let arr = [1, -2, 3, 4, -5];
let leftIndex = [0, 2, 1];
let rightIndex = [4, 3, 3];
let res = maxPrefixes(arr, leftIndex, rightIndex);
console.log(res.join(" "));

Output
6 7 5 

[Expected Approach] – Using Segment Tree – O(q * log n) Time and O(n) Space

The idea is to use a segment tree to efficiently answer range queries for the maximum prefix sum. Each node in the segment tree stores both the total sum of its segment and the maximum prefix sum within that segment, so that when two segments are merged, the overall prefix sum can be computed as the maximum of the left segment’s prefix sum and the sum of the left segment plus the right segment’s prefix sum.

Segment Tree Structure:

The segment tree is structured as an array-based binary tree. The leaf nodes represent individual elements of the input array. Each internal node represents a merged segment where its stored sum is the total sum of the leaves in its segment and its prefix sum is computed as the maximum between the left child’s prefix sum and the left child’s sum plus the right child’s prefix sum. For a node at index i, its left child is at 2i+1, its right child at 2i+2, and its parent is at (i-1)/2.

Follow the below given steps:

  • Create a segment tree where each node stores two values: the sum of the segment and the maximum prefix sum for that segment.
  • For leaf nodes, initialize both values with the corresponding element from the input array.
  • For internal nodes, merge the two child nodes by setting the node’s sum as the sum of its children and its prefix sum as the maximum of the left child’s prefix sum and the sum of the left child plus the right child’s prefix sum.
  • To answer a query, perform a range query on the segment tree to retrieve the combined node for the specified range, and then return its stored maximum prefix sum as the answer.
C++
#include <bits/stdc++.h>
using namespace std;

// structure to store the segment tree
struct Node {
    int sum;
    int prefix;
    Node() {
        sum = 0;
        prefix = 0;
    }
};

// function to build the segment tree
void build(vector<int> &arr, int ind, 
    int start, int end, vector<Node> &tree) {

    // if there is only one element
    // store it in current node
    if (start == end) {        
        tree[ind].sum = arr[start];
        tree[ind].prefix = arr[start];
    } 
    else {
        int mid = (start + end) / 2;

        // If there are more than one elements,
        // then recur for left and right subtrees
        build(arr, 2 * ind + 1, start, mid, tree);
        build(arr, 2 * ind + 2, mid + 1, end, tree);

        // adds the sum and stores in the
        // mid position of segment tree
        tree[ind].sum = tree[2 * ind + 1].sum + 
                        tree[2 * ind + 2].sum;

        // stores the max of prefix-sum either
        // from right or from left.
        tree[ind].prefix = max(tree[2 * ind + 1].prefix, 
        tree[2 * ind + 1].sum + tree[2 * ind + 2].prefix);
    }
}

// function to do the range query in the 
// segment tree for the maximum prefix sum
Node query(int ind, int start, int end, 
    int l, int r, vector<Node> &tree) {

    // to store the result
    Node result;
    result.sum = result.prefix = -1;

    // If segment of this node is outside the given 
    // range, then return the minimum value.
    if (start > r || end < l)
        return result;

    // If segment of this node is a part of given
    // range, then return the node of the segment
    if (start >= l && end <= r)
        return tree[ind];

    int mid = (start + end) / 2;

    // if left segment of this node falls out of
    // range, then recur in the right side of the tree
    if (l > mid)
        return query(2 * ind + 2, mid + 1, end, l, r, tree);

    // if right segment of this node falls out of
    // range, then recur in the left side of the tree
    if (r <= mid)
        return query(2 * ind + 1, start, mid, l, r, tree);

    // If a part of this segment overlaps 
    // with the given range
    Node left = query(2 * ind + 1, start, mid, l, r, tree);
    Node right = query(2 * ind + 2, mid + 1, end, l, r, tree);

    // adds the sum of the left and right segment
    result.sum = left.sum + right.sum;

    // stores the max of prefix-sum
    result.prefix = max(left.prefix, left.sum + right.prefix);

    // returns the value
    return result;
}

// Function to return the maximum prefix sum for each query
vector<int> maxPrefixes(vector<int>& arr, 
    vector<int>& leftIndex, vector<int>& rightIndex) {
    int n = arr.size();

    // to store the segment tree
    vector<Node> tree(4 * n);

    // build the segment tree
    build(arr, 0, 0, n - 1, tree);

    int q = leftIndex.size();

    // to store the results
    vector<int> res;

    for(int i = 0; i < q; i++) {
        int l = leftIndex[i];
        int r = rightIndex[i];

        // query the segment tree
        Node result = query(0, 0, n - 1, l, r, tree);

        // store the result
        res.push_back(result.prefix);
    }

    return res;
}

int main() {
    vector<int> arr = {1, -2, 3, 4, -5};
    vector<int> leftIndex = {0, 2, 1};
    vector<int> rightIndex = {4, 3, 3};
    vector<int> res = maxPrefixes(arr, leftIndex, rightIndex);
    for(int i = 0; i < res.size(); i++) {
        cout << res[i] << " ";
    }
    return 0;
}
Java
import java.util.*;

class GfG {

    // Function to build the segment tree
    static class Node {
        int sum;
        int prefix;
        Node() {
            sum = 0;
            prefix = 0;
        }
    }
    
    // Function to build the segment tree
    static void build(int[] arr, int ind, int start, int end, Node[] tree) {
        
        // if there is only one element
        if (start == end) {
            tree[ind].sum = arr[start];
            tree[ind].prefix = arr[start];
        } else {
            int mid = (start + end) / 2;
            
            // If there are more than one elements,
            build(arr, 2 * ind + 1, start, mid, tree);
            build(arr, 2 * ind + 2, mid + 1, end, tree);
            
            // adds the sum and stores in the
            tree[ind].sum = tree[2 * ind + 1].sum + tree[2 * ind + 2].sum;
            
            // stores the max of prefix-sum either
            tree[ind].prefix = Math.max(tree[2 * ind + 1].prefix, tree[2 * ind + 1].sum + tree[2 * ind + 2].prefix);
        }
    }
    
    // Function to do the range query in the 
    // segment tree for the maximum prefix sum
    static Node query(int ind, int start, int end, int l, int r, Node[] tree) {
        Node result = new Node();
        result.sum = result.prefix = -1;
        
        // If segment of this node is outside the given 
        // range, then return the minimum value.
        if (start > r || end < l)
            return result;
        
        // If segment of this node is a part of given
        // range, then return the node of the segment
        if (start >= l && end <= r)
            return tree[ind];
        
        int mid = (start + end) / 2;
        
        // if left segment of this node falls out of
        // range, then recur in the right side of the tree
        if (l > mid)
            return query(2 * ind + 2, mid + 1, end, l, r, tree);
        
        // if right segment of this node falls out of
        // range, then recur in the left side of the tree
        if (r <= mid)
            return query(2 * ind + 1, start, mid, l, r, tree);
        
        Node left = query(2 * ind + 1, start, mid, l, r, tree);
        Node right = query(2 * ind + 2, mid + 1, end, l, r, tree);
        
        // adds the sum of the left and right segment
        result.sum = left.sum + right.sum;
        
        // stores the max of prefix-sum
        result.prefix = Math.max(left.prefix, left.sum + right.prefix);
        
        // returns the value
        return result;
    }
    
    // Function to return the maximum prefix sum for each query
    static List<Integer> maxPrefixes(int[] arr, List<Integer> leftIndex, List<Integer> rightIndex) {
        int n = arr.length;
        
        // to store the segment tree
        Node[] tree = new Node[4 * n];
        for (int i = 0; i < 4 * n; i++) {
            tree[i] = new Node();
        }
        
        // build the segment tree
        build(arr, 0, 0, n - 1, tree);
        
        int q = leftIndex.size();
        
        // to store the results
        List<Integer> res = new ArrayList<>();
        
        for (int i = 0; i < q; i++) {
            int l = leftIndex.get(i);
            int r = rightIndex.get(i);
            
            // query the segment tree
            Node result = query(0, 0, n - 1, l, r, tree);
            
            // store the result
            res.add(result.prefix);
        }
        
        return res;
    }
    
    public static void main(String[] args) {
        int[] arr = {1, -2, 3, 4, -5};
        List<Integer> leftIndex = Arrays.asList(0, 2, 1);
        List<Integer> rightIndex = Arrays.asList(4, 3, 3);
        List<Integer> res = maxPrefixes(arr, leftIndex, rightIndex);
        for (int i = 0; i < res.size(); i++) {
            System.out.print(res.get(i) + " ");
        }
    }
}
Python
# Function to build the segment tree
class Node:
    def __init__(self):
        self.sum = 0
        self.prefix = 0

# Function to build the segment tree
def build(arr, ind, start, end, tree):
    # if there is only one element
    if start == end:
        tree[ind].sum = arr[start]
        tree[ind].prefix = arr[start]
    else:
        mid = (start + end) // 2
        
        # If there are more than one elements,
        build(arr, 2 * ind + 1, start, mid, tree)
        build(arr, 2 * ind + 2, mid + 1, end, tree)
        
        # adds the sum and stores in the
        tree[ind].sum = tree[2 * ind + 1].sum + tree[2 * ind + 2].sum
        
        # stores the max of prefix-sum either
        tree[ind].prefix = max(tree[2 * ind + 1].prefix, tree[2 * ind + 1].sum + tree[2 * ind + 2].prefix)

# Function to do the range query in the 
# segment tree for the maximum prefix sum
def query(ind, start, end, l, r, tree):
    result = Node()
    result.sum = result.prefix = -1
    
    # If segment of this node is outside the given 
    # range, then return the minimum value.
    if start > r or end < l:
        return result
    
    # If segment of this node is a part of given
    # range, then return the node of the segment
    if start >= l and end <= r:
        return tree[ind]
    
    mid = (start + end) // 2
    
    # if left segment of this node falls out of
    # range, then recur in the right side of the tree
    if l > mid:
        return query(2 * ind + 2, mid + 1, end, l, r, tree)
    
    # if right segment of this node falls out of
    # range, then recur in the left side of the tree
    if r <= mid:
        return query(2 * ind + 1, start, mid, l, r, tree)
    
    left = query(2 * ind + 1, start, mid, l, r, tree)
    right = query(2 * ind + 2, mid + 1, end, l, r, tree)
    
    # adds the sum of the left and right segment
    result.sum = left.sum + right.sum
    
    # stores the max of prefix-sum
    result.prefix = max(left.prefix, left.sum + right.prefix)
    
    # returns the value
    return result

# Function to return the maximum prefix sum for each query
def maxPrefixes(arr, leftIndex, rightIndex):
    n = len(arr)
    
    # to store the segment tree
    tree = [Node() for _ in range(4 * n)]
    
    # build the segment tree
    build(arr, 0, 0, n - 1, tree)
    
    q = len(leftIndex)
    
    # to store the results
    res = []
    
    for i in range(q):
        l = leftIndex[i]
        r = rightIndex[i]
        
        # query the segment tree
        result = query(0, 0, n - 1, l, r, tree)
        
        # store the result
        res.append(result.prefix)
    
    return res

if __name__ == "__main__":
    arr = [1, -2, 3, 4, -5]
    leftIndex = [0, 2, 1]
    rightIndex = [4, 3, 3]
    res = maxPrefixes(arr, leftIndex, rightIndex)
    print(" ".join(map(str, res)))
C#
using System;
using System.Collections.Generic;

class Node {
    public int sum;
    public int prefix;
    public Node() {
        sum = 0;
        prefix = 0;
    }
}

class GfG {

    // Function to build the segment tree
    static void build(int[] arr, int ind, int start, int end, Node[] tree) {
        
        // if there is only one element
        if (start == end) {
            tree[ind].sum = arr[start];
            tree[ind].prefix = arr[start];
        } else {
            int mid = (start + end) / 2;
            
            // If there are more than one elements,
            build(arr, 2 * ind + 1, start, mid, tree);
            build(arr, 2 * ind + 2, mid + 1, end, tree);
            
            // adds the sum and stores in the
            tree[ind].sum = tree[2 * ind + 1].sum + tree[2 * ind + 2].sum;
            
            // stores the max of prefix-sum either
            tree[ind].prefix = Math.Max(tree[2 * ind + 1].prefix, tree[2 * ind + 1].sum + tree[2 * ind + 2].prefix);
        }
    }
    
    // Function to do the range query in the 
    // segment tree for the maximum prefix sum
    static Node query(int ind, int start, int end, int l, int r, Node[] tree) {
        Node result = new Node();
        result.sum = result.prefix = -1;
        
        // If segment of this node is outside the given 
        // range, then return the minimum value.
        if (start > r || end < l)
            return result;
        
        // If segment of this node is a part of given
        // range, then return the node of the segment
        if (start >= l && end <= r)
            return tree[ind];
        
        int mid = (start + end) / 2;
        
        // if left segment of this node falls out of
        // range, then recur in the right side of the tree
        if (l > mid)
            return query(2 * ind + 2, mid + 1, end, l, r, tree);
        
        // if right segment of this node falls out of
        // range, then recur in the left side of the tree
        if (r <= mid)
            return query(2 * ind + 1, start, mid, l, r, tree);
        
        Node left = query(2 * ind + 1, start, mid, l, r, tree);
        Node right = query(2 * ind + 2, mid + 1, end, l, r, tree);
        
        // adds the sum of the left and right segment
        result.sum = left.sum + right.sum;
        
        // stores the max of prefix-sum
        result.prefix = Math.Max(left.prefix, left.sum + right.prefix);
        
        // returns the value
        return result;
    }
    
    // Function to return the maximum prefix sum for each query
    static List<int> maxPrefixes(int[] arr, List<int> leftIndex, List<int> rightIndex) {
        int n = arr.Length;
        
        // to store the segment tree
        Node[] tree = new Node[4 * n];
        for (int i = 0; i < 4 * n; i++) {
            tree[i] = new Node();
        }
        
        // build the segment tree
        build(arr, 0, 0, n - 1, tree);
        
        int q = leftIndex.Count;
        
        // to store the results
        List<int> res = new List<int>();
        
        for (int i = 0; i < q; i++) {
            int l = leftIndex[i];
            int r = rightIndex[i];
            
            // query the segment tree
            Node result = query(0, 0, n - 1, l, r, tree);
            
            // store the result
            res.Add(result.prefix);
        }
        
        return res;
    }
    
    public static void Main() {
        int[] arr = {1, -2, 3, 4, -5};
        List<int> leftIndex = new List<int> {0, 2, 1};
        List<int> rightIndex = new List<int> {4, 3, 3};
        List<int> res = maxPrefixes(arr, leftIndex, rightIndex);
        for (int i = 0; i < res.Count; i++) {
            Console.Write(res[i] + " ");
        }
    }
}
JavaScript
// Function to build the segment tree
class Node {
    constructor() {
        this.sum = 0;
        this.prefix = 0;
    }
}

// Function to build the segment tree
function build(arr, ind, start, end, tree) {
    
    // if there is only one element
    if (start === end) {
        tree[ind].sum = arr[start];
        tree[ind].prefix = arr[start];
    } else {
        let mid = Math.floor((start + end) / 2);
        
        // If there are more than one elements,
        build(arr, 2 * ind + 1, start, mid, tree);
        build(arr, 2 * ind + 2, mid + 1, end, tree);
        
        // adds the sum and stores in the
        tree[ind].sum = tree[2 * ind + 1].sum + tree[2 * ind + 2].sum;
        
        // stores the max of prefix-sum either
        tree[ind].prefix = Math.max(tree[2 * ind + 1].prefix, tree[2 * ind + 1].sum + tree[2 * ind + 2].prefix);
    }
}

// Function to do the range query in the 
// segment tree for the maximum prefix sum
function query(ind, start, end, l, r, tree) {
    let result = new Node();
    result.sum = result.prefix = -1;
    
    // If segment of this node is outside the given 
    // range, then return the minimum value.
    if (start > r || end < l)
        return result;
    
    // If segment of this node is a part of given
    // range, then return the node of the segment
    if (start >= l && end <= r)
        return tree[ind];
    
    let mid = Math.floor((start + end) / 2);
    
    // if left segment of this node falls out of
    // range, then recur in the right side of the tree
    if (l > mid)
        return query(2 * ind + 2, mid + 1, end, l, r, tree);
    
    // if right segment of this node falls out of
    // range, then recur in the left side of the tree
    if (r <= mid)
        return query(2 * ind + 1, start, mid, l, r, tree);
    
    let left = query(2 * ind + 1, start, mid, l, r, tree);
    let right = query(2 * ind + 2, mid + 1, end, l, r, tree);
    
    // adds the sum of the left and right segment
    result.sum = left.sum + right.sum;
    
    // stores the max of prefix-sum
    result.prefix = Math.max(left.prefix, left.sum + right.prefix);
    
    // returns the value
    return result;
}

// Function to return the maximum prefix sum for each query
function maxPrefixes(arr, leftIndex, rightIndex) {
    let n = arr.length;
    
    // to store the segment tree
    let tree = new Array(4 * n);
    for (let i = 0; i < 4 * n; i++) {
        tree[i] = new Node();
    }
    
    // build the segment tree
    build(arr, 0, 0, n - 1, tree);
    
    let q = leftIndex.length;
    
    // to store the results
    let res = [];
    
    for (let i = 0; i < q; i++) {
        let l = leftIndex[i];
        let r = rightIndex[i];
        
        // query the segment tree
        let result = query(0, 0, n - 1, l, r, tree);
        
        // store the result
        res.push(result.prefix);
    }
    
    return res;
}

let arr = [1, -2, 3, 4, -5];
let leftIndex = [0, 2, 1];
let rightIndex = [4, 3, 3];
let res = maxPrefixes(arr, leftIndex, rightIndex);
console.log(res.join(" "));

Output
6 7 5 


Next Article
Practice Tags :

Similar Reads