Queries for greatest pair sum in the given index range using Segment Tree
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:
- Leaf Nodes are the elements of the input array.
- 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) |
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)
Please Login to comment...