Open In App

Queries for greatest pair sum in the given index range using Segment Tree

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] containing N integers and an array Q[] representing the range [L, R], the task is to find the greatest pair sum value in the range [L, R] where 0 ? L ? R ? N – 1. Examples:

Input: arr[] = {1, 3, 2, 7, 9, 11}, Q[] = {1, 4} 
Output: 16 
Explanation: The greatest pair sum in range 1 to 4 is 7 + 9 = 16.

 Input: arr[] = {0, 1, 2, 3, 4, 5, 6, 7}, Q[] = {5, 7} 
Output: 13 
Explanation: The greatest pair sum in range 5 to 7 is 6 + 7 = 13.

Naive Approach: The naive approach for this problem is to run a loop from [L, R] and find the two greatest elements in the given range. Their sum is always the greatest pair sum in the given index range. The time complexity of this approach is O(N) for every query. Efficient Approach: The idea is to use a Segment tree in order to perform some preprocessing and find the value for every query in logarithmic time. Representation of the Segment tree:

  1. Leaf Nodes are the elements of the input array.
  2. Each internal node contains the greatest pair sum as well as the maximum element of all leaves under it.

An array representation of the tree is used to represent the Segment Tree. For each node at the index ‘i’, the left child is at index ((2 * i) + 1), the right child is at the index ((2 * i) + 2) and the parent is at the index ((i – 1)/2). Construction of Segment Tree from given array:

  • We start with a segment from the given array arr[].
  • At each step, we divide the current segment into two halves(if it has not yet become a segment of length 1).
  • The above step is performed recursively again on the obtained halves of the array.
  • For every segment, we store the maximum value as well as the greatest pair sum in a segment tree node.
  • The maximum pair sum and the maximum value for every node can be found as:

Maximum Pair Sum-> maximum( Left child’s maximum pair sum, Right child’s maximum pair sum, Left child’s maximum value + Right child’s maximum value) Maximum Value -> maximum(Left child’s maximum value, Right child’s maximum value )

Below is the implementation of the above approach: 

CPP




// C++ program for range greatest
// pair sum query using segment tree
 
#include <bits/stdc++.h>
using namespace std;
 
// Defining the node
struct node {
    int maxVal, greatestPSum;
} st[100009];
 
// A utility function
node util(node x, node y)
{
    node ans;
 
    // Find the maximum pair sum
    ans.greatestPSum
        = max(x.maxVal + y.maxVal,
            max(x.greatestPSum,
                y.greatestPSum));
    // Find the maximum value
    ans.maxVal = max(x.maxVal, y.maxVal);
    return ans;
}
 
// A utility function to get the
// middle index from corner indexes.
int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
 
/* A recursive function to get the
greatest pair sum value in a given range
of array indexes. Here:
 
index --> Index of current node in the
        segment tree. Initially 0 is
        passed as root is always at index 0
ss & se --> Starting and ending indexes
            of the segment represented
            by current node, i.e., st[index]
qs & qe --> Starting and ending indexes
            of query range */
node query(int ss, int se, int qs,
        int qe, int index)
{
    // If segment of this node is a part
    // of given range, then return
    // the min of the segment
    if (qs <= ss && qe >= se)
        return st[index];
 
    node temp;
    temp.maxVal = -1,
    temp.greatestPSum = -1;
 
    // If segment of this node
    // is outside the given range
    if (se < qs || ss > qe)
        return temp;
 
    // If a part of this segment
    // overlaps with the given range
    int mid = getMid(ss, se);
    return util(query(ss, mid, qs,
                    qe, 2 * index + 1),
 
                query(mid + 1, se, qs,
                    qe, 2 * index + 2));
}
 
// Function to return the greatest pair
// sum in the range from index
// qs (query start) to qe (query end)
node checkQuery(int n, int qs, int qe)
{
    node temp;
    temp.maxVal = -1, temp.greatestPSum = -1;
 
    // Check for erroneous input values
    if (qs < 0 || qe > n - 1 || qs > qe) {
        cout << "Invalid Input";
        return temp;
    }
 
    return query(0, n - 1, qs, qe, 0);
}
 
// A recursive function that constructs
// Segment Tree for array[ss..se].
// si is index of current node in segment tree
node constructST(int arr[], int ss,
                int se, int si)
{
    // If there is one element in array,
    // store it in current node of
    // segment tree and return
    if (ss == se) {
        st[si].maxVal = arr[ss];
        st[si].greatestPSum = 0;
        return st[si];
    }
 
    // If there are more than one elements,
    // then recur for left and right subtrees
    int mid = getMid(ss, se);
    st[si] = util(constructST(arr, ss, mid,
                            si * 2 + 1),
 
                constructST(arr, mid + 1, se,
                            si * 2 + 2));
    return st[si];
}
 
// Utility function to find the
// greatest pair sum for the given
// queries
void operation(int arr[], int n,
            int qs, int qe)
{
    // Build segment tree from given array
    constructST(arr, 0, n - 1, 0);
 
    node ans = checkQuery(n, qs, qe);
 
    // Print minimum value in arr[qs..qe]
    cout << ans.greatestPSum << endl;
}
 
// Driver code
int main()
{
    int arr[] = { 1, 3, 2, 7, 9, 11 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    int L = 1;
    int R = 4;
 
    operation(arr, n, L, R);
 
    return 0;
}


Java




import java.util.*;
 
class Node {
    int maxVal, greatestPSum;
 
    Node(int maxVal, int greatestPSum) {
        this.maxVal = maxVal;
        this.greatestPSum = greatestPSum;
    }
}
 
public class Main {
    static Node[] st = new Node[100009];
 
    static Node util(Node x, Node y) {
        Node ans = new Node(0, 0);
 
        ans.greatestPSum = Math.max(x.maxVal + y.maxVal,
                Math.max(x.greatestPSum, y.greatestPSum));
 
        ans.maxVal = Math.max(x.maxVal, y.maxVal);
 
        return ans;
    }
 
    static int getMid(int s, int e) {
        return s + (e - s) / 2;
    }
 
    static Node query(int ss, int se, int qs, int qe, int index) {
        if (qs <= ss && qe >= se)
            return st[index];
 
        Node temp = new Node(-1, -1);
 
        if (se < qs || ss > qe)
            return temp;
 
        int mid = getMid(ss, se);
        return util(query(ss, mid, qs, qe, 2 * index + 1),
                query(mid + 1, se, qs, qe, 2 * index + 2));
    }
 
    static Node checkQuery(int n, int qs, int qe) {
        Node temp = new Node(-1, -1);
 
        if (qs < 0 || qe > n - 1 || qs > qe) {
            System.out.println("Invalid Input");
            return temp;
        }
 
        return query(0, n - 1, qs, qe, 0);
    }
 
    static Node constructST(int arr[], int ss, int se, int si) {
        if (ss == se) {
            st[si] = new Node(arr[ss], 0);
            return st[si];
        }
 
        int mid = getMid(ss, se);
        st[si] = util(constructST(arr, ss, mid, si * 2 + 1),
                constructST(arr, mid + 1, se, si * 2 + 2));
        return st[si];
    }
 
    static void operation(int arr[], int n, int qs, int qe) {
        constructST(arr, 0, n - 1, 0);
 
        Node ans = checkQuery(n, qs, qe);
 
        System.out.println(ans.greatestPSum);
    }
 
    public static void main(String args[]) {
        int arr[] = { 1, 3, 2, 7, 9, 11 };
        int n = arr.length;
 
        int L = 1;
        int R = 4;
 
        operation(arr, n, L, R);
    }
}


Python3




#  Python program for range greatest
#  pair sum query using segment tree
 
# A utility function
def util(x, y):
    ans = {}
    # Find the maximum pair sum
    ans['greatestPSum'] = max(x['maxVal'] + y['maxVal'], max(x['greatestPSum'], y['greatestPSum']))
     
    # Find the maximum value
    ans['maxVal'] = max(x['maxVal'], y['maxVal'])
    return ans
     
     
# A utility function to get the
# middle index from corner indexes.
def getMid(s, e):
    return s + (e - s) // 2
 
 
#  A recursive function to get the
# greatest pair sum value in a given range
# of array indexes. Here:
 
# index --> Index of current node in the
#         segment tree. Initially 0 is
#         passed as root is always at index 0
# ss & se --> Starting and ending indexes
#             of the segment represented
#             by current node, i.e., st[index]
# qs & qe --> Starting and ending indexes
#             of query range
def query(ss, se, qs, qe, index, st):
     
     
    # If segment of this node is a part
    # of given range, then return
    # the min of the segment
    if qs <= ss and qe >= se:
        return st[index]
     
    temp = {}
    temp['maxVal'], temp['greatestPSum'] = -1, -1
     
    # If segment of this node
    # is outside the given range
    if se < qs or ss > qe:
        return temp
     
    # If a part of this segment
    # overlaps with the given range
    mid = getMid(ss, se)
    return util(query(ss, mid, qs, qe, 2 * index + 1, st), query(mid + 1, se, qs, qe, 2 * index + 2, st))
 
 
# Function to return the greatest pair
#  sum in the range from index
#  qs (query start) to qe (query end)
def checkQuery(n, qs, qe, st):
    temp = {}
    temp['maxVal'], temp['greatestPSum'] = -1, -1
     
    # Check for erroneous input values
    if qs < 0 or qe > n - 1 or qs > qe:
        print("Invalid Input")
        return temp
     
    return query(0, n - 1, qs, qe, 0, st)
 
 
#  A recursive function that constructs
#  Segment Tree for array[ss..se].
#  si is index of current node in segment tree
def constructST(arr, ss, se, si, st):
     
     
    # If there is one element in array,
    # store it in current node of
    # segment tree and return
    if ss == se:
        st[si] = {'maxVal': arr[ss], 'greatestPSum': 0}
        return st[si]
     
     
    # If there are more than one elements,
    # then recur for left and right subtrees
    mid = getMid(ss, se)
    st[si] = util(constructST(arr, ss, mid, si * 2 + 1, st), constructST(arr, mid + 1, se, si * 2 + 2, st))
    return st[si]
 
# Utility function to find the
# greatest pair sum for the given
# queries
def operation(arr, n, qs, qe):
    st = [{} for i in range(4*n)]
     
    # Build segment tree from given array
    constructST(arr, 0, n - 1, 0, st)
    ans = checkQuery(n, qs, qe, st)
     
    # Print minimum value in arr[qs..qe]
    print(ans['greatestPSum'])
 
# Driver code
arr = [1, 3, 2, 7, 9, 11]
n = len(arr)
 
L, R = 1, 4
 
operation(arr, n, L, R)


C#




using System;
 
public class Node
{
    public int maxVal, greatestPSum;
 
    public Node(int maxVal, int greatestPSum)
    {
        this.maxVal = maxVal;
        this.greatestPSum = greatestPSum;
    }
}
 
public class MainClass
{
    static Node[] st = new Node[100009];
 
    static Node Util(Node x, Node y)
    {
        Node ans = new Node(0, 0);
 
        ans.greatestPSum = Math.Max(x.maxVal + y.maxVal,
            Math.Max(x.greatestPSum, y.greatestPSum));
 
        ans.maxVal = Math.Max(x.maxVal, y.maxVal);
 
        return ans;
    }
 
    static int GetMid(int s, int e)
    {
        return s + (e - s) / 2;
    }
 
    static Node Query(int ss, int se, int qs, int qe, int index)
    {
        if (qs <= ss && qe >= se)
            return st[index];
 
        Node temp = new Node(-1, -1);
 
        if (se < qs || ss > qe)
            return temp;
 
        int mid = GetMid(ss, se);
        return Util(Query(ss, mid, qs, qe, 2 * index + 1),
            Query(mid + 1, se, qs, qe, 2 * index + 2));
    }
 
    static Node CheckQuery(int n, int qs, int qe)
    {
        Node temp = new Node(-1, -1);
 
        if (qs < 0 || qe > n - 1 || qs > qe)
        {
            Console.WriteLine("Invalid Input");
            return temp;
        }
 
        return Query(0, n - 1, qs, qe, 0);
    }
 
    static Node ConstructST(int[] arr, int ss, int se, int si)
    {
        if (ss == se)
        {
            st[si] = new Node(arr[ss], 0);
            return st[si];
        }
 
        int mid = GetMid(ss, se);
        st[si] = Util(ConstructST(arr, ss, mid, si * 2 + 1),
            ConstructST(arr, mid + 1, se, si * 2 + 2));
        return st[si];
    }
 
    static void Operation(int[] arr, int n, int qs, int qe)
    {
        ConstructST(arr, 0, n - 1, 0);
 
        Node ans = CheckQuery(n, qs, qe);
 
        Console.WriteLine(ans.greatestPSum);
    }
 
    public static void Main()
    {
        int[] arr = { 1, 3, 2, 7, 9, 11 };
        int n = arr.Length;
 
        int L = 1;
        int R = 4;
 
        Operation(arr, n, L, R);
    }
}


Javascript




// A utility function
function util(x, y) {
  let ans = {};
  // Find the maximum pair sum
  ans['greatestPSum'] = Math.max(x['maxVal'] + y['maxVal'], Math.max(x['greatestPSum'], y['greatestPSum']));
 
  // Find the maximum value
  ans['maxVal'] = Math.max(x['maxVal'], y['maxVal']);
  return ans;
}
 
// A utility function to get the
// middle index from corner indexes.
function getMid(s, e) {
  return s + Math.floor((e - s) / 2);
}
 
//  A recursive function to get the
// greatest pair sum value in a given range
// of array indexes. Here:
// index --> Index of current node in the
//         segment tree. Initially 0 is
//         passed as root is always at index 0
// ss & se --> Starting and ending indexes
//             of the segment represented
//             by current node, i.e., st[index]
// qs & qe --> Starting and ending indexes
//             of query range
function query(ss, se, qs, qe, index, st) {
  // If segment of this node is a part
  // of given range, then return
  // the min of the segment
  if (qs <= ss && qe >= se) {
    return st[index];
  }
 
  let temp = {};
  temp['maxVal'] = -1;
  temp['greatestPSum'] = -1;
 
  // If segment of this node
  // is outside the given range
  if (se < qs || ss > qe) {
    return temp;
  }
 
  // If a part of this segment
  // overlaps with the given range
  let mid = getMid(ss, se);
  return util(
    query(ss, mid, qs, qe, 2 * index + 1, st),
    query(mid + 1, se, qs, qe, 2 * index + 2, st)
  );
}
 
// Function to return the greatest pair
// sum in the range from index
// qs (query start) to qe (query end)
function checkQuery(n, qs, qe, st) {
  let temp = {};
  temp['maxVal'] = -1;
  temp['greatestPSum'] = -1;
 
  // Check for erroneous input values
  if (qs < 0 || qe > n - 1 || qs > qe) {
    console.log("Invalid Input");
    return temp;
  }
 
  return query(0, n - 1, qs, qe, 0, st);
}
 
//  A recursive function that constructs
//  Segment Tree for array[ss..se].
//  si is index of current node in segment tree
function constructST(arr, ss, se, si, st) {
  // If there is one element in array,
  // store it in current node of
  // segment tree and return
  if (ss == se) {
    st[si] = {'maxVal': arr[ss], 'greatestPSum': 0};
    return st[si];
  }
 
  // If there are more than one elements,
  // then recur for left and right subtrees
  let mid = getMid(ss, se);
  st[si] = util(constructST(arr, ss, mid, si * 2 + 1, st), constructST(arr, mid + 1, se, si * 2 + 2, st))
    return st[si]
}
 
// Utility function to find the
// greatest pair sum for the given
// queries
function operation(arr, n, qs, qe)
{
    let st = []
    for (var i = 0; i < 4 * n; i++)
        st.push({})
 
    // Build segment tree from given array
    constructST(arr, 0, n - 1, 0, st)
    let ans = checkQuery(n, qs, qe, st)
     
    // Print minimum value in arr[qs..qe]
    console.log(ans['greatestPSum'])
}
 
// Driver code
let arr = [1, 3, 2, 7, 9, 11]
let n = arr.length
 
let L = 1
let R = 4
 
operation(arr, n, L, R)


Output:

16

Time Complexity:

  • The time complexity for tree construction is O(N) where N is the size of the array.
  • The time complexity for each query is O(log(N)) where N is the size of the array.

Auxiliary Space: O(N)



Last Updated : 27 Apr, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads