Given an array arr[] of size N and a 2D array Q[][] consisting of queries of following two types:
- 1 X Y: Update the array element at index X with Y.
- 2 K: Print the position of the first array element greater than or equal to K. If there is no such index, then print -1.
Examples:
Input : arr[] = { 1, 3, 2, 4, 6 }, Q[][] = {{2, 5}, {1, 3, 5}, {2, 4}, {2, 8}}
Output: 5 3 -1
Explanation:
Query1: Since arr[4] > 5, the position of arr[4] is 5.
Query2: Updating arr[2] with 5 modifies arr[] to {1, 3, 5, 4, 6}
Query3: Since arr[2] > 4, the position of arr[4] is 5.
Query4: No array element is greater than 8.Input : arr[] = {1, 2, 3}, N = 3, Q[][] = {{2, 2}, {1, 3, 5}, {2, 10}}
Output: 2 -1
Naive Approach: The simplest approach to solve this problem is as follows:
- For a query of type 1, then update arr[X – 1] to Y.
- Otherwise, traverse the array and print the position of the first array element which is greater than or equal to K.
Time Complexity: O(N * |Q|)
Auxiliary Space: O(1)
Efficient Approach: The above approach can be optimized by using segment tree. The idea is to build and update the tree using the concept of Range Maximum Query with Node Update. Follow the steps below to solve the problem:
- Build a segment tree with each node consisting of the maximum of its subtree.
- Update operation can be performed by using the concept of Range Maximum Query with Node Update
- Position of the first array element which is greater than or equal to K can be found by recursively checking for the following conditions:
- Check if the root of the left subtree is greater than or equal to K or not. If found to be true, then find the position from the left subtree. If no such array element is found in the left subtree, then recursively find the position in the right subtree.
- Otherwise, recursively find the position in the right subtree.
- Finally, print the position of an array element which is greater than or equal to K.
Below is the implementation of above approach :
C++
// C++ program to implement // the above approach #include <bits/stdc++.h> using namespace std; // Function to find the mid // of start and end int getMid( int s, int e) { return s + (e - s) / 2; } // Function to update nodes at position index void updateValue( int arr[], int * st, int ss, int se, int index, int value, int node) { // If index is out of range if (index < ss || index > se) { cout << "Invalid Input" << endl; return ; } // If a leaf node is found if (ss == se) { // update value in array arr[index] = value; // Update value in // the segment tree st[node] = value; } else { // Stores mid of ss and se int mid = getMid(ss, se); // If index is less than or // equal to mid if (index >= ss && index <= mid) { // Recursively call for left subtree updateValue(arr, st, ss, mid, index, value, 2 * node + 1); } else { // Recursively call for right subtree updateValue(arr, st, mid + 1, se, index, value, 2 * node + 2); } // Update st[node] st[node] = max(st[2 * node + 1], st[2 * node + 2]); } return ; } // Function to find the position of first element // which is greater than or equal to X int findMinimumIndex( int * st, int ss, int se, int K, int si) { // If no such element found in current // subtree which is greater than or // equal to K if (st[si] < K) return 1e9; // If current node is leaf node if (ss == se) { // If value of current node // is greater than or equal to X if (st[si] >= K) { return ss; } return 1e9; } // Stores mid of ss and se int mid = getMid(ss, se); int l = 1e9; // If root of left subtree is // greater than or equal to K if (st[2 * si + 1] >= K) l = min(l, findMinimumIndex(st, ss, mid, K, 2 * si + 1)); // If no such array element is // found in the left subtree if (l == 1e9 && st[2 * si + 2] >= K) l = min(l, findMinimumIndex(st, mid + 1, se, K, 2 * si + 2)); return l; } // Function to build a segment tree int Build( int arr[], int ss, int se, int * st, int si) { // If current node is leaf node if (ss == se) { st[si] = arr[ss]; return arr[ss]; } // store mid of ss and se int mid = getMid(ss, se); // Stores maximum of left subtree and rightsubtree st[si] = max(Build(arr, ss, mid, st, si * 2 + 1), Build(arr, mid + 1, se, st, si * 2 + 2)); return st[si]; } // Function to initialize a segment tree // for the given array int * constructST( int arr[], int n) { // Height of segment tree int x = ( int )( ceil (log2(n))); // Maximum size of segment tree int max_size = 2 * ( int ) pow (2, x) - 1; // Allocate memory int * st = new int [max_size]; // Fill the allocated memory st Build(arr, 0, n - 1, st, 0); // Return the constructed segment tree return st; } // Function to perform the queries of // the given type void PerformQueries( int arr[], int N, vector<vector< int > > Q) { // Build segment tree for the given array int * st = constructST(arr, N); // Traverse the query array for ( int i = 0; i < Q.size(); i++) { // If query of type 1 found if (Q[i][0] == 1) updateValue(arr, st, 0, N - 1, Q[i][1] - 1, 5, 0); else { // Stores index of first array element // which is greater than or equal // to Q[i][1] int f = findMinimumIndex(st, 0, N - 1, Q[i][1], 0); if (f < N) cout << f + 1 << " " ; else cout << -1 << " " ; } } } // Driver Code int main() { int arr[] = { 1, 3, 2, 4, 6 }; vector<vector< int > > Q{ { 2, 5 }, { 1, 3, 5 }, { 2, 4 }, { 2, 8 } }; int N = sizeof (arr) / sizeof (arr[0]); PerformQueries(arr, N, Q); return 0; } |
Java
/*package whatever //do not write package name here */ import java.io.*; class GFG { // Function to find the mid // of start and end static int getMid( int s, int e) { return s + (e - s) / 2 ; } static void updateValue( int arr[], int [] st, int ss, int se, int index, int value, int node) { // If index is out of range if (index < ss || index > se) { System.out.println( "Invalid Input" ); return ; } // If a leaf node is found if (ss == se) { // update value in array arr[index] = value; // Update value in // the segment tree st[node] = value; } else { // Stores mid of ss and se int mid = getMid(ss, se); // If index is less than or // equal to mid if (index >= ss && index <= mid) { // Recursively call for left subtree updateValue(arr, st, ss, mid, index, value, 2 * node + 1 ); } else { // Recursively call for right subtree updateValue(arr, st, mid + 1 , se, index, value, 2 * node + 2 ); } // Update st[node] st[node] = Math.max(st[ 2 * node + 1 ], st[ 2 * node + 2 ]); } } // Function to find the position of first element // which is greater than or equal to X static int findMinimumIndex( int [] st, int ss, int se, int K, int si) { // If no such element found in current // subtree which is greater than or // equal to K if (st[si] < K) return 1000000000 ; // If current node is leaf node if (ss == se) { // If value of current node // is greater than or equal to X if (st[si] >= K) { return ss; } return 1000000000 ; } // Stores mid of ss and se int mid = getMid(ss, se); int l = 1000000000 ; // If root of left subtree is // greater than or equal to K if (st[ 2 * si + 1 ] >= K) l = Math.min(l, findMinimumIndex(st, ss, mid, K, 2 * si + 1 )); // If no such array element is // found in the left subtree if (l == 1e9 && st[ 2 * si + 2 ] >= K) l = Math.min(l, findMinimumIndex(st, mid + 1 , se, K, 2 * si + 2 )); return l; } // Function to build a segment tree static int Build( int arr[], int ss, int se, int [] st, int si) { // If current node is leaf node if (ss == se) { st[si] = arr[ss]; return arr[ss]; } // store mid of ss and se int mid = getMid(ss, se); // Stores maximum of left subtree and rightsubtree st[si] = Math.max( Build(arr, ss, mid, st, si * 2 + 1 ), Build(arr, mid + 1 , se, st, si * 2 + 2 )); return st[si]; } // Function to initialize a segment tree // for the given array static int [] constructST( int arr[], int n) { // Height of segment tree int x = ( int )Math.ceil(Math.log(n) / Math.log( 2 )); // Maximum size of segment tree int max_size = 2 * ( int )Math.pow( 2 , x) - 1 ; // Allocate memory int [] st = new int [max_size]; // Fill the allocated memory st Build(arr, 0 , n - 1 , st, 0 ); // Return the constructed segment tree return st; } static void PerformQueries( int arr[], int N, int [][] Q) { // Build segment tree for the given array int [] st = constructST(arr, N); // Traverse the query array for ( int i = 0 ; i < Q.length; i++) { // If query of type 1 found if (Q[i][ 0 ] == 1 ) updateValue(arr, st, 0 , N - 1 , Q[i][ 1 ] - 1 , 5 , 0 ); else { // Stores index of first array element // which is greater than or equal // to Q[i][1] int f = findMinimumIndex(st, 0 , N - 1 , Q[i][ 1 ], 0 ); if (f < N) System.out.print(f + 1 + " " ); else System.out.print(- 1 + " " ); } } } // Driver Code public static void main(String[] args) { int arr[] = { 1 , 3 , 2 , 4 , 6 }; int [][] Q = { { 2 , 5 }, { 1 , 3 , 5 }, { 2 , 4 }, { 2 , 8 } }; int N = arr.length; PerformQueries(arr, N, Q); } } // This code is contributed by hemanthsawarna1506 |
Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.