Queries to evaluate the given equation in a range [L, R]
Given an array arr[] consisting of N integers and queries Q[][] of the form {L, R} where 0 ≤ L < R ≤ N – 1, the task for each query is to calculate the following equation :
KL | KL + 1 |…| KR – 1
where Ki = (arr[i] ^ arr[i+1]) | (arr[i] ~ arr[i+1]),
“~” represents binary XNOR,
“^” represents binary XOR ,
“|” represents binary OR
Examples:
Input: arr[] = {5, 2, 3, 0}, Q[][] = {{1, 3}, {0, 2}}
Output: 3 7
Explanation:
Query 1: L = 1, R = 3 : K1 = (2 ^ 3) | (2 ~ 3) = (3 | 2) = 3, K2 = (3 ^ 0) | (3 ~ 0) = (3 | 0) = 3.
Therefore, K1 | K2 = (3 | 3) = 3
Query 2: L = 0, R = 2 : K0 = 7, K1 = 3.
Therefore, K0 | K1 = (7 | 3) = 7Input: arr[] = {4, 0, 1, 2}, Q[][] = {{1, 3}}
Output: 3
Naive Approach: The simplest approach to solve this problem is to traverse the indices [L, R – 1], and for each element, calculate Ki, where L ≤ i < R.
Time Complexity: O(N * sizeof(Q))
Efficient Approach: To optimize the above approach, the idea is to use a Segment Tree or Sparse Table. Follow the steps below to solve the problem:
- The following observation needs to be made:
XOR operation sets only those bits which are either set in arri or in arri+1
XNOR sets those bits which are either set in both ai and ai+1 or not set in both.
- Taking OR of both of these operations, all the bits up to the largest of the max(MSB(arri), MSB(arri+1)) will be set.
- Therefore, find the largest number, using Segment Tree, in between the given indices and set all of its bits to 1, to obtain the required answer.
- Print the answer.
Below is the implementation of the above approach:
C++
// C++ Program to implement // the above approach #include <bits/stdc++.h> using namespace std; // Function to obtain the // middle index of the range int getMid( int s, int e) { return s + (e - s) / 2; } /* Recursive function to get the sum of values in the given range from the array. The following are parameters for this function. st -> Pointer to segment tree node -> Index of current node in the segment tree ss & se -> Starting and ending indexes of the segment represented by current node, i.e., st[node] l & r -> Starting and ending indexes of range query */ int MaxUtil( int * st, int ss, int se, int l, int r, int node) { // If the segment of this node lies // completely within the given range if (l <= ss && r >= se) // Return maximum in the segment return st[node]; // If the segment of this node lies // outside the given range if (se < l || ss > r) return -1; // If segment of this node lies // partially in the given range int mid = getMid(ss, se); return max(MaxUtil(st, ss, mid, l, r, 2 * node + 1), MaxUtil(st, mid + 1, se, l, r, 2 * node + 2)); } // Function to return the maximum in the // range from [l, r] int getMax( int * st, int n, int l, int r) { // Check for erroneous input values if (l < 0 || r > n - 1 || l > r) { printf ( "Invalid Input" ); return -1; } return MaxUtil(st, 0, n - 1, l, r, 0); } // Function to construct Segment Tree // for the subarray [ss..se] int constructSTUtil( int arr[], int ss, int se, int * st, int si) { // For a single element if (ss == se) { st[si] = arr[ss]; return arr[ss]; } // Otherwise int mid = getMid(ss, se); // Recur for left subtree st[si] = max(constructSTUtil(arr, ss, mid, st, si * 2 + 1), // Recur for right subtree constructSTUtil(arr, mid + 1, se, st, si * 2 + 2)); return st[si]; } // Function to construct Segment Tree from // 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 constructSTUtil(arr, 0, n - 1, st, 0); // Return the constructed Segment Tree return st; } // Driver Code int main() { int arr[] = { 5, 2, 3, 0 }; int n = sizeof (arr) / sizeof (arr[0]); // Build the Segment Tree // from the given array int * st = constructST(arr, n); vector<vector< int > > Q = { { 1, 3 }, { 0, 2 } }; for ( int i = 0; i < Q.size(); i++) { int max = getMax(st, n, Q[i][0], Q[i][1]); int ok = 0; for ( int i = 30; i >= 0; i--) { if ((max & (1 << i)) != 0) ok = 1; if (!ok) continue ; max |= (1 << i); } cout << max << " " ; } return 0; } |
Java
// Java Program to implement // the above approach import java.util.*; class GFG{ // Function to obtain the // middle index of the range static int getMid( int s, int e) { return s + (e - s) / 2 ; } /* Recursive function to get the sum of values in the given range from the array. The following are parameters for this function. st .Pointer to segment tree node .Index of current node in the segment tree ss & se.Starting and ending indexes of the segment represented by current node, i.e., st[node] l & r.Starting and ending indexes of range query */ static int MaxUtil( int [] st, int ss, int se, int l, int r, int node) { // If the segment of this node lies // completely within the given range if (l <= ss && r >= se) // Return maximum in the segment return st[node]; // If the segment of this node lies // outside the given range if (se < l || ss > r) return - 1 ; // If segment of this node lies // partially in the given range int mid = getMid(ss, se); return Math.max(MaxUtil(st, ss, mid, l, r, 2 * node + 1 ), MaxUtil(st, mid + 1 , se, l, r, 2 * node + 2 )); } // Function to return the maximum in the // range from [l, r] static int getMax( int []st, int n, int l, int r) { // Check for erroneous input values if (l < 0 || r > n - 1 || l > r) { System.out.printf( "Invalid Input" ); return - 1 ; } return MaxUtil(st, 0 , n - 1 , l, r, 0 ); } // Function to construct Segment Tree // for the subarray [ss..se] static int constructSTUtil( int arr[], int ss, int se, int [] st, int si) { // For a single element if (ss == se) { st[si] = arr[ss]; return arr[ss]; } // Otherwise int mid = getMid(ss, se); // Recur for left subtree st[si] = Math.max(constructSTUtil(arr, ss, mid, st, si * 2 + 1 ), // Recur for right subtree constructSTUtil(arr, mid + 1 , se, st, si * 2 + 2 )); return st[si]; } // Function to construct Segment Tree from // the given array static int [] constructST( int arr[], int n) { // Height of Segment Tree int x = ( int )(Math.ceil(Math.log(n))); // 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 constructSTUtil(arr, 0 , n - 1 , st, 0 ); // Return the constructed Segment Tree return st; } // Driver Code public static void main(String[] args) { int arr[] = { 5 , 2 , 3 , 0 }; int n = arr.length; // Build the Segment Tree // from the given array int []st = constructST(arr, n); int [][] Q = { { 1 , 3 }, { 0 , 2 } }; for ( int i = 0 ; i < Q.length; i++) { int max = getMax(st, n, Q[i][ 0 ], Q[i][ 1 ]); int ok = 0 ; for ( int j = 30 ; j >= 0 ; j--) { if ((max & ( 1 << j)) != 0 ) ok = 1 ; if (ok<= 0 ) continue ; max |= ( 1 << j); } System.out.print(max+ " " ); } } } // This code is contributed by gauravrajput1 |
Python3
# Python3 program to implement # the above approach import math # Function to obtain the # middle index of the range def getMid(s, e): return (s + (e - s) / / 2 ) def MaxUtil(st, ss, se, l, r, node): # If the segment of this node lies # completely within the given range if (l < = ss and r > = se): # Return maximum in the segment return st[node] # If the segment of this node lies # outside the given range if (se < l or ss > r): return - 1 # If segment of this node lies # partially in the given range mid = getMid(ss, se) return max (MaxUtil(st, ss, mid, l, r, 2 * node + 1 ), MaxUtil(st, mid + 1 , se, l, r, 2 * node + 2 )) # Function to return the maximum # in the range from [l, r] def getMax(st, n, l, r): # Check for erroneous input values if (l < 0 or r > n - 1 or l > r): print ( "Invalid Input" ) return - 1 return MaxUtil(st, 0 , n - 1 , l, r, 0 ) # Function to construct Segment Tree # for the subarray [ss..se] def constructSTUtil(arr, ss, se, st, si): # For a single element if (ss = = se): st[si] = arr[ss] return arr[ss] # Otherwise mid = getMid(ss, se) # Recur for left subtree st[si] = max (constructSTUtil(arr, ss, mid, st, si * 2 + 1 ), constructSTUtil(arr, mid + 1 , se, st, si * 2 + 2 )) return st[si] # Function to construct Segment Tree # from the given array def constructST(arr, n): # Height of Segment Tree x = ( int )(math.ceil(math.log(n))) # Maximum size of Segment Tree max_size = 2 * ( int )( pow ( 2 , x)) - 1 # Allocate memory st = [ 0 ] * max_size # Fill the allocated memory constructSTUtil(arr, 0 , n - 1 , st, 0 ) # Return the constructed Segment Tree return st # Driver Code arr = [ 5 , 2 , 3 , 0 ] n = len (arr) # Build the Segment Tree # from the given array st = constructST(arr, n) Q = [ [ 1 , 3 ], [ 0 , 2 ] ] for i in range ( len (Q)): Max = getMax(st, n, Q[i][ 0 ], Q[i][ 1 ]) ok = 0 for j in range ( 30 , - 1 , - 1 ): if (( Max & ( 1 << j)) ! = 0 ): ok = 1 if (ok < = 0 ): continue Max | = ( 1 << j) print ( Max , end = " " ) # This code is contributed by divyesh072019 |
C#
// C# Program to implement // the above approach using System; class GFG { // Function to obtain the // middle index of the range static int getMid( int s, int e) { return s + (e - s) / 2; } /* Recursive function to get the sum of values in the given range from the array. The following are parameters for this function: st--> Pointer to segment tree node--> Index of current node in segment tree ss & se--> Starting and ending indexes of the segment represented by current node, i.e., st[node] l & r--> Starting and ending indexes of range query */ static int MaxUtil( int [] st, int ss, int se, int l, int r, int node) { // If the segment of this node lies // completely within the given range if (l <= ss && r >= se) // Return maximum in the segment return st[node]; // If the segment of this node lies // outside the given range if (se < l || ss > r) return -1; // If segment of this node lies // partially in the given range int mid = getMid(ss, se); return Math.Max( MaxUtil(st, ss, mid, l, r, 2 * node + 1), MaxUtil(st, mid + 1, se, l, r, 2 * node + 2)); } // Function to return the maximum // in the range from [l, r] static int getMax( int [] st, int n, int l, int r) { // Check for erroneous input values if (l < 0 || r > n - 1 || l > r) { Console.Write( "Invalid Input" ); return -1; } return MaxUtil(st, 0, n - 1, l, r, 0); } // Function to construct Segment Tree // for the subarray [ss..se] static int constructSTUtil( int [] arr, int ss, int se, int [] st, int si) { // For a single element if (ss == se) { st[si] = arr[ss]; return arr[ss]; } // Otherwise int mid = getMid(ss, se); // Recur for left subtree st[si] = Math.Max( constructSTUtil(arr, ss, mid, st, si * 2 + 1), // Recur for right subtree constructSTUtil(arr, mid + 1, se, st, si * 2 + 2)); return st[si]; } // Function to construct Segment Tree // from the given array static int [] constructST( int [] arr, int n) { // Height of Segment Tree int x = ( int )(Math.Ceiling(Math.Log(n))); // 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 constructSTUtil(arr, 0, n - 1, st, 0); // Return the constructed Segment Tree return st; } // Driver Code public static void Main(String[] args) { int [] arr = {5, 2, 3, 0}; int n = arr.Length; // Build the Segment Tree // from the given array int [] st = constructST(arr, n); int [, ] Q = {{1, 3}, {0, 2}}; for ( int i = 0; i < Q.GetLength(0); i++) { int max = getMax(st, n, Q[i, 0], Q[i, 1]); int ok = 0; for ( int j = 30; j >= 0; j--) { if ((max & (1 << j)) != 0) ok = 1; if (ok <= 0) continue ; max |= (1 << j); } Console.Write(max + " " ); } } } // This code is contributed by Amit Katiyar |
Javascript
<script> // JavaScript program for the above approach // Function to obtain the // middle index of the range function getMid(s, e) { return (s + Math.floor((e - s) / 2)); } /* Recursive function to get the sum of values in the given range from the array. The following are parameters for this function. st .Pointer to segment tree node .Index of current node in the segment tree ss & se.Starting and ending indexes of the segment represented by current node, i.e., st[node] l & r.Starting and ending indexes of range query */ function MaxUtil(st, ss, se, l, r, node) { // If the segment of this node lies // completely within the given range if (l <= ss && r >= se) // Return maximum in the segment return st[node]; // If the segment of this node lies // outside the given range if (se < l || ss > r) return -1; // If segment of this node lies // partially in the given range let mid = getMid(ss, se); return Math.max(MaxUtil(st, ss, mid, l, r, 2 * node + 1), MaxUtil(st, mid + 1, se, l, r, 2 * node + 2)); } // Function to return the maximum in the // range from [l, r] function getMax(st, n, l, r) { // Check for erroneous input values if (l < 0 || r > n - 1 || l > r) { document.write( "Invalid Input" ); return -1; } return MaxUtil(st, 0, n - 1, l, r, 0); } // Function to construct Segment Tree // for the subarray [ss..se] function constructSTUtil(arr, ss, se, st, si) { // For a single element if (ss == se) { st[si] = arr[ss]; return arr[ss]; } // Otherwise let mid = getMid(ss, se); // Recur for left subtree st[si] = Math.max(constructSTUtil(arr, ss, mid, st, si * 2 + 1), // Recur for right subtree constructSTUtil(arr, mid + 1, se, st, si * 2 + 2)); return st[si]; } // Function to construct Segment Tree from // the given array function constructST(arr, n) { // Height of Segment Tree let x = (Math.ceil(Math.log(n))); // Maximum size of Segment Tree let max_size = 2 * Math.pow(2, x) - 1; // Allocate memory let st = Array.from({length: max_size}, (_, i) => 0); // Fill the allocated memory constructSTUtil(arr, 0, n - 1, st, 0); // Return the constructed Segment Tree return st; } // Driver Code let arr = [ 5, 2, 3, 0 ]; let n = arr.length; // Build the Segment Tree // from the given array let st = constructST(arr, n); let Q = [[ 1, 3 ], [ 0, 2 ]]; for (let i = 0; i < Q.length; i++) { let max = getMax(st, n, Q[i][0], Q[i][1]); let ok = 0; for (let j = 30; j >= 0; j--) { if ((max & (1 << j)) != 0) ok = 1; if (ok<=0) continue ; max |= (1 << j); } document.write(max+ " " ); } </script> |
3 7
Time Complexity: O(N*log(sizeof(Q))
Auxiliary Space: O(N)
Related Topic: Segment Tree
Please Login to comment...