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.
Table of Content
[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.
#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;
}
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) + " ");
}
}
}
# 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)))
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] + " ");
}
}
}
// 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.
#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;
}
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) + " ");
}
}
}
# 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)))
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] + " ");
}
}
}
// 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