Maximize the summation of numbers in a maximum of K moves in range [L, R]

Given an array arr[] of N integers and Q queries. Each query consists of 3 integers L, R and K. You can move from index i to index i + 1 in a single step or stay in that particular index in a single step. You can move from L to R index in a maximum of K steps and print the summation of every number you were at in every step including the L-th number. The task is to maximize the summation in a maximum of K moves. If we cannot move from L to R in K steps then print “No”.

Examples:

Input: arr[] = {1, 3, 2, -4, -5}, q = {
{0, 2, 2},
{0, 2, 4},
{3, 4, 1},
{0, 4, 2}}
Output:
6
12
-9
No



For first query:
In first step move from 0th index to 1st index, hence 1 + 3 = 4
In second step move from 1st index to 2nd index, hence 4 + 2 = 6

For second query:
In first step move from 0th index to 1st index, hence 1 + 3 = 4
In second step stay at the 1st index, hence 4 + 3 = 7
In third step again stay at the 1st index, hence 7 + 3 = 10
In fourth step move from 1st index to 2nd index only, hence 10 + 2 = 12

A naive approach is to check first if L – R > K, if it is then we cannot move from L to R index in K steps. Iterate from L to R, get the sum of all elements between L and R. Then find the maximum element in the range L and R and the answer will be the sum of elements in the range and (K – (R – L)) * maximum. If the maximum is a negative number we exactly perform R – L moves else we perform the extra steps at the maximum number index in the range [L, R].
Time Complexity: O(R – L) per query.

An efficient approach is to use segment tree in the range [L, R] to find the maximum number and find the sum in the range using prefix sum.

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
  
// Function to create the tree
void tree(int low, int high, int pos,
          int b[], int a[], int n)
{
    // Leaf nodes
    if (low == high) {
        b[pos] = a[high];
        return;
    }
    int mid = (high + low) / 2;
  
    // Left subtree
    tree(low, mid, 2 * pos + 1, b, a, n);
  
    // Right subtree
    tree(mid + 1, high, 2 * pos + 2, b, a, n);
  
    // Merge the maximum
    b[pos] = max(b[2 * pos + 1], b[2 * pos + 2]);
}
  
// Function that returns the maximum in range L and R
int rangemax(int s, int e, int low, int high,
             int pos, int b[], int a[], int n)
{
    // Complete overlap
    if (low <= s && high >= e)
        return b[pos];
  
    // Out of range completely
    if (e < low || s > high)
        return INT_MIN;
    int mid = (s + e) / 2;
  
    // Find maximum in left and right subtrees
    int left = rangemax(s, mid, low, high,
                        2 * pos + 1, b, a, n);
    int right = rangemax(mid + 1, e, low, high,
                         2 * pos + 2, b, a, n);
  
    // Return the maximum of both
    return max(left, right);
}
  
// Function that solves a query
int solveQuery(int l, int r, int k, int n, int a[],
               int b[], int prefix[])
{
  
    // If there are ko
    if (r - l > k)
        return -1;
  
    // Find maximum in range L and R
    int maximum = rangemax(0, n - 1, l, r, 0, b, a, n);
  
    // If maximum is 0
    if (maximum < 0)
        maximum = 0;
  
    // Find the prefix sum
    int rangesum = prefix[r];
  
    // If not first element
    if (l > 0)
        rangesum -= prefix[l - 1];
  
    // Get the answer
    int answer = rangesum + (k - (r - l)) * maximum;
  
    return answer;
}
  
// Function that solves the queries
void solveQueries(int n, int a[], int b[],
                  int prefix[], int queries[][3], int q)
{
  
    // Solve all the queries
    for (int i = 0; i < q; i++) {
        int ans = solveQuery(queries[i][0], queries[i][1],
                             queries[i][2], n, a, b, prefix);
        if (ans != -1)
            cout << ans << endl;
        else
            cout << "No" << endl;
    }
}
  
// Function to find the prefix sum
void findPrefixSum(int prefix[], int a[], int n)
{
    prefix[0] = a[0];
    for (int i = 1; i < n; i++) {
        prefix[i] = prefix[i - 1] + a[i];
    }
}
  
// Driver code
int main()
{
    int a[] = { 1, 3, 2, -4, -5 };
    int n = sizeof(a) / sizeof(a[0]);
  
    // Array for segment tree
    int b[5 * n];
  
    // Create segment tree
    tree(0, n - 1, 0, b, a, n);
  
    int prefix[n];
  
    // Fill prefix sum array
    findPrefixSum(prefix, a, n);
  
    // Queries
    int queries[][3] = { { 0, 2, 2 },
                         { 0, 2, 4 },
                         { 3, 4, 1 },
                         { 0, 4, 2 } };
  
    int q = sizeof(queries) / sizeof(queries[0]);
    solveQueries(n, a, b, prefix, queries, q);
  
    return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of the approach
  
class GFG
{
  
// Function to create the tree
static void tree(int low, int high, int pos,
        int b[], int a[], int n)
{
    // Leaf nodes
    if (low == high)
    {
        b[pos] = a[high];
        return;
    }
    int mid = (high + low) / 2;
  
    // Left subtree
    tree(low, mid, 2 * pos + 1, b, a, n);
  
    // Right subtree
    tree(mid + 1, high, 2 * pos + 2, b, a, n);
  
    // Merge the maximum
    b[pos] = Math.max(b[2 * pos + 1], b[2 * pos + 2]);
}
  
// Function that returns the maximum in range L and R
static int rangemax(int s, int e, int low, int high,
            int pos, int b[], int a[], int n)
{
    // Complete overlap
    if (low <= s && high >= e)
        return b[pos];
  
    // Out of range completely
    if (e < low || s > high)
        return Integer.MIN_VALUE;
    int mid = (s + e) / 2;
  
    // Find maximum in left and right subtrees
    int left = rangemax(s, mid, low, high,
                        2 * pos + 1, b, a, n);
    int right = rangemax(mid + 1, e, low, high,
                        2 * pos + 2, b, a, n);
  
    // Return the maximum of both
    return Math.max(left, right);
}
  
// Function that solves a query
static int solveQuery(int l, int r, int k, int n, int a[],
                                    int b[], int prefix[])
{
  
    // If there are ko
    if (r - l > k)
        return -1;
  
    // Find maximum in range L and R
    int maximum = rangemax(0, n - 1, l, r, 0, b, a, n);
  
    // If maximum is 0
    if (maximum < 0)
        maximum = 0;
  
    // Find the prefix sum
    int rangesum = prefix[r];
  
    // If not first element
    if (l > 0)
        rangesum -= prefix[l - 1];
  
    // Get the answer
    int answer = rangesum + (k - (r - l)) * maximum;
  
    return answer;
}
  
// Function that solves the queries
static void solveQueries(int n, int a[], int b[],
                int prefix[], int queries[][], int q)
{
  
    // Solve all the queries
    for (int i = 0; i < q; i++)
    {
        int ans = solveQuery(queries[i][0], queries[i][1],
                            queries[i][2], n, a, b, prefix);
        if (ans != -1)
            System.out.println(ans);
        else
            System.out.println("No" );
    }
}
  
// Function to find the prefix sum
static void findPrefixSum(int prefix[], int a[], int n)
{
    prefix[0] = a[0];
    for (int i = 1; i < n; i++) 
    {
        prefix[i] = prefix[i - 1] + a[i];
    }
}
  
// Driver code
public static void main(String[] args)
{
    int a[] = { 1, 3, 2, -4, -5 };
    int n = a.length;
  
    // Array for segment tree
    int b[] = new int[5 * n];
  
    // Create segment tree
    tree(0, n - 1, 0, b, a, n);
  
    int prefix[] = new int[n];
  
    // Fill prefix sum array
    findPrefixSum(prefix, a, n);
  
    // Queries
    int queries[][] = { { 0, 2, 2 },
                        { 0, 2, 4 },
                        { 3, 4, 1 },
                        { 0, 4, 2 } };
  
    int q = queries.length;
    solveQueries(n, a, b, prefix, queries, q);
  
}
}
  
/* This code contributed by PrinciRaj1992 */

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program to implement
// the above approach
using System;
  
class GFG
{
  
// Function to create the tree
static void tree(int low, int high, int pos,
                    int []b, int []a, int n)
{
    // Leaf nodes
    if (low == high)
    {
        b[pos] = a[high];
        return;
    }
    int mid = (high + low) / 2;
  
    // Left subtree
    tree(low, mid, 2 * pos + 1, b, a, n);
  
    // Right subtree
    tree(mid + 1, high, 2 * pos + 2, b, a, n);
  
    // Merge the maximum
    b[pos] = Math.Max(b[2 * pos + 1], b[2 * pos + 2]);
}
  
// Function that returns the maximum in range L and R
static int rangemax(int s, int e, int low, int high,
            int pos, int []b, int []a, int n)
{
    // Complete overlap
    if (low <= s && high >= e)
        return b[pos];
  
    // Out of range completely
    if (e < low || s > high)
        return int.MinValue;
    int mid = (s + e) / 2;
  
    // Find maximum in left and right subtrees
    int left = rangemax(s, mid, low, high,
                        2 * pos + 1, b, a, n);
    int right = rangemax(mid + 1, e, low, high,
                        2 * pos + 2, b, a, n);
  
    // Return the maximum of both
    return Math.Max(left, right);
}
  
// Function that solves a query
static int solveQuery(int l, int r, int k, int n, int []a,
                                    int []b, int []prefix)
{
  
    // If there are ko
    if (r - l > k)
        return -1;
  
    // Find maximum in range L and R
    int maximum = rangemax(0, n - 1, l, r, 0, b, a, n);
  
    // If maximum is 0
    if (maximum < 0)
        maximum = 0;
  
    // Find the prefix sum
    int rangesum = prefix[r];
  
    // If not first element
    if (l > 0)
        rangesum -= prefix[l - 1];
  
    // Get the answer
    int answer = rangesum + (k - (r - l)) * maximum;
  
    return answer;
}
  
// Function that solves the queries
static void solveQueries(int n, int []a, int []b,
                int []prefix, int [,]queries, int q)
{
  
    // Solve all the queries
    for (int i = 0; i < q; i++)
    {
        int ans = solveQuery(queries[i,0], queries[i,1],
                            queries[i,2], n, a, b, prefix);
        if (ans != -1)
            Console.WriteLine(ans);
        else
            Console.WriteLine("No" );
    }
}
  
// Function to find the prefix sum
static void findPrefixSum(int []prefix, int []a, int n)
{
    prefix[0] = a[0];
    for (int i = 1; i < n; i++) 
    {
        prefix[i] = prefix[i - 1] + a[i];
    }
}
  
// Driver code
public static void Main(String[] args)
{
    int []a = { 1, 3, 2, -4, -5 };
    int n = a.Length;
  
    // Array for segment tree
    int []b = new int[5 * n];
  
    // Create segment tree
    tree(0, n - 1, 0, b, a, n);
  
    int []prefix = new int[n];
  
    // Fill prefix sum array
    findPrefixSum(prefix, a, n);
  
    // Queries
    int [,]queries = { { 0, 2, 2 },
                        { 0, 2, 4 },
                        { 3, 4, 1 },
                        { 0, 4, 2 } };
  
    int q = queries.GetLength(0);
    solveQueries(n, a, b, prefix, queries, q);
  
}
}
  
// This code has been contributed by 29AjayKumar

chevron_right


Output:

6
12
-9
No

Time Complexity: O(Log N) per query.
Auxiliary Space: O(N log N)



My Personal Notes arrow_drop_up

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 : princiraj1992, 29AjayKumar