Given an array of N elements, initially all a[i] = 0. Q queries need to be performed. Each query contains three integers l, r, and x and you need to change all a[i] to (a[i] | x) for all l ≤ i ≤ r and return the array after executing Q queries.
Examples:
Input: N = 3, Q = 2, U = {{1, 3, 1}, {1, 3, 2}}
Output: a[] = {3, 3, 3}
Explanation: Initially, all elements of the array are 0. After execution of the first query, all elements become 1 and after execution of the second query all elements become 3.Input: N = 3, Q = 2, U = {{1, 2, 1}, {3, 3, 2}}
Output: a[] = {1, 1, 2}
Explanation: {0, 0, 0] => {1, 1, 0} => {1, 1, 2}
Naive Approach:
- Initialize the array a of the size N with all elements set to 0.
- For each query in U:
– Iterate over the range from the l to r (inclusive).
– For each index i, perform the bitwise OR operation between the current value at a[i] and x, and update a[i] with the result. - Return the final array a after executing all queries.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h> using namespace std; // Function to perform operations on an array based on given // queries vector< int > GFG( int N, int Q, vector<vector< int > >& U) { vector< int > a(N, 0); // Process each query in U for ( const auto & query : U) { // Start index of range int l = query[0]; // End index of range int r = query[1]; // Value to be ORed int x = query[2]; // Perform OR operation on elements within the range // [l, r] for ( int i = l - 1; i < r; ++i) { a[i] |= x; } } return a; } int main() { // Number of elements in the array int N = 3; // Number of queries int Q = 2; vector<vector< int > > U = { { 1, 2, 1 }, { 3, 3, 2 } }; // Queries: [l, r, x] // Call the function to perform operations on the array vector< int > result = GFG(N, Q, U); // Print the resulting array for ( const auto & num : result) { cout << num << " " ; } cout << endl; return 0; } |
Java
// Java code for the above approach: import java.util.ArrayList; import java.util.List; public class Main { // Function to perform operations on an array based on given // queries public static List<Integer> GFG( int N, int Q, List<List<Integer>> U) { List<Integer> a = new ArrayList<>(N); for ( int i = 0 ; i < N; i++) { a.add( 0 ); } // Process each query in U for (List<Integer> query : U) { // Start index of range int l = query.get( 0 ); // End index of range int r = query.get( 1 ); // Value to be ORed int x = query.get( 2 ); // Perform OR operation on elements within the range // [l, r] for ( int i = l - 1 ; i < r; i++) { a.set(i, a.get(i) | x); } } return a; } public static void main(String[] args) { // Number of elements in the array int N = 3 ; // Number of queries int Q = 2 ; List<List<Integer>> U = new ArrayList<>(); U.add(List.of( 1 , 2 , 1 )); U.add(List.of( 3 , 3 , 2 )); // Queries: [l, r, x] // Call the function to perform operations on the array List<Integer> result = GFG(N, Q, U); // Print the resulting array for ( int num : result) { System.out.print(num + " " ); } System.out.println(); } } // This code is contributed by Utkarsh Kumar |
C#
using System; using System.Collections.Generic; class Program { // Function to perform operations on an // array based on given queries static List< int > Geek( int N, int Q, List<List< int >> U) { List< int > a = new List< int >( new int [N]); // Process each query in U foreach ( var query in U) { // Start index of range int l = query[0]; // End index of range int r = query[1]; // Value to be ORed int x = query[2]; // Perform OR operation on elements within // the range [l, r] for ( int i = l - 1; i < r; ++i) { a[i] |= x; } } return a; } static void Main( string [] args) { // Number of elements in the array int N = 3; // Number of queries int Q = 2; List<List< int >> U = new List<List< int >> { new List< int > { 1, 2, 1 }, new List< int > { 3, 3, 2 }, }; // Queries: [l, r, x] List< int > result = Geek(N, Q, U); // Print the resulting array foreach ( var num in result) { Console.Write(num + " " ); } Console.WriteLine(); } } |
1 1 2
Time complexity: O(N * Q), where N is the number of elements in the array and Q is the number of queries.
Auxiliary space: O(N) because it uses an additional vector a to store the resulting array of size N.
Efficient Approach:
To solve this problem efficiently, we have to use the concept of difference arrays for each bit.
Below are the steps for the above approach:
- Create a 2D difference array say, dp[][] of size N*20. For every index, keep an array of size 20 to store the bits and initialize every index as 0.
- For each query of l, r, and x, increment those indices of the dp[l] array where the bit position of x is set and decrement those indexes of the dp[r+1] array where the bit position of x is set.
- For each bit, we will run a loop from i=1 to N. And add the value of the previous index to the value of the current index, dp[i][j] += dp[i-1][j].
- Declare an array, say a[] which will be the answer array.
- Every inner array of dp[][] array represents a number. That means every index of the inner array represents the bit of a number. So put the numbers in their appropriate positions and return them.
Below is the implementation of the above approach:
C++
// C++ code for the above approach: #include <bits/stdc++.h> using namespace std; vector< int > updateQuery( int N, int Q, vector<vector< int > >& U) { // Code here vector< int > a(N); fill(a.begin(), a.end(), 0); int dp[N][20]; for ( int i = 0; i < N; i++) { for ( int j = 0; j < 20; j++) dp[i][j] = 0; } for ( int j = 0; j < U.size(); j++) { for ( int i = 0; i < 20; i++) { if (U[j][2] & (1 << i)) { dp[U[j][0] - 1][i]++; if (U[j][1] < N) dp[U[j][1]][i]--; } } } for ( int j = 0; j < 20; j++) { for ( int i = 1; i < N; i++) { dp[i][j] += dp[i - 1][j]; } } for ( int i = 0; i < N; i++) { int ans = 0; for ( int j = 0; j < 20; j++) { if (dp[i][j]) ans += (1 << j); } a[i] = ans; } return a; } // Drivers code int main() { int N = 3, Q = 2; vector<vector< int > > u = { { 1, 2, 1 }, { 3, 3, 2 } }; // Function Call vector< int > ans = updateQuery(N, Q, u); for ( auto it : ans) cout << it << " " ; return 0; } |
Java
// Java code for the above approach: import java.util.*; class GFG { public static void main(String[] args) { int N = 3 , Q = 2 ; List<List<Integer>> U = new ArrayList<>(); U.add(Arrays.asList( 1 , 2 , 1 )); U.add(Arrays.asList( 3 , 3 , 2 )); List<Integer> ans = updateQuery(N, Q, U); for ( int it : ans) System.out.print(it + " " ); } static List<Integer> updateQuery( int N, int Q, List<List<Integer>> U) { List<Integer> a = new ArrayList<>(); for ( int i = 0 ; i < N; i++) a.add( 0 ); int [][] dp = new int [N][ 20 ]; for ( int i = 0 ; i < N; i++) { for ( int j = 0 ; j < 20 ; j++) dp[i][j] = 0 ; } for ( int j = 0 ; j < U.size(); j++) { for ( int i = 0 ; i < 20 ; i++) { if ((U.get(j).get( 2 ) & ( 1 << i)) != 0 ) { dp[U.get(j).get( 0 ) - 1 ][i]++; if (U.get(j).get( 1 ) < N) dp[U.get(j).get( 1 )][i]--; } } } for ( int j = 0 ; j < 20 ; j++) { for ( int i = 1 ; i < N; i++) { dp[i][j] += dp[i - 1 ][j]; } } for ( int i = 0 ; i < N; i++) { int ansVal = 0 ; for ( int j = 0 ; j < 20 ; j++) { if (dp[i][j] != 0 ) ansVal += ( 1 << j); } a.set(i, ansVal); } return a; } } |
Python3
# Python3 code for the above approach: def updateQuery(N, Q, U): # Code here a = [ 0 ] * N dp = [[ 0 ] * 20 for i in range (N)] for j in range ( len (U)): for i in range ( 20 ): if (U[j][ 2 ] & ( 1 << i)): dp[U[j][ 0 ] - 1 ][i] + = 1 if (U[j][ 1 ] < N): dp[U[j][ 1 ]][i] - = 1 for j in range ( 20 ): for i in range ( 1 , N): dp[i][j] + = dp[i - 1 ][j] for i in range (N): ans = 0 for j in range ( 20 ): if (dp[i][j]): ans + = ( 1 << j) a[i] = ans return a # Drivers code N = 3 Q = 2 U = [ [ 1 , 2 , 1 ], [ 3 , 3 , 2 ] ] # Function Call ans = updateQuery(N, Q, U) for it in ans: print (it, end = " " ) |
C#
// C# code for the above approach: using System; using System.Collections.Generic; class GFG { static List< int > UpdateQuery( int N, int Q, List<List< int > > U) { List< int > a = new List< int >( new int [N]); int [, ] dp = new int [N, 20]; for ( int i = 0; i < N; i++) { for ( int j = 0; j < 20; j++) { dp[i, j] = 0; } } for ( int j = 0; j < U.Count; j++) { for ( int i = 0; i < 20; i++) { if ((U[j][2] & (1 << i)) != 0) { dp[U[j][0] - 1, i]++; if (U[j][1] < N) { dp[U[j][1], i]--; } } } } for ( int j = 0; j < 20; j++) { for ( int i = 1; i < N; i++) { dp[i, j] += dp[i - 1, j]; } } for ( int i = 0; i < N; i++) { int ans = 0; for ( int j = 0; j < 20; j++) { if (dp[i, j] != 0) { ans += (1 << j); } } a[i] = ans; } return a; } static void Main( string [] args) { int N = 3, Q = 2; List<List< int > > U = new List<List< int > >(); U.Add( new List< int >{ 1, 2, 1 }); U.Add( new List< int >{ 3, 3, 2 }); // Function Call List< int > ans = UpdateQuery(N, Q, U); foreach ( var item in ans) { Console.Write(item + " " ); } } } |
Javascript
// JavaScript code for the above approach: function updateQuery(N, Q, U) { let a = new Array(N).fill(0); let dp = new Array(N); for (let i = 0; i < N; i++) { dp[i] = new Array(20).fill(0); } for (let j = 0; j < U.length; j++) { for (let i = 0; i < 20; i++) { if (U[j][2] & (1 << i)) { dp[U[j][0] - 1][i]++; if (U[j][1] < N) { dp[U[j][1]][i]--; } } } } for (let j = 0; j < 20; j++) { for (let i = 1; i < N; i++) { dp[i][j] += dp[i - 1][j]; } } for (let i = 0; i < N; i++) { let ans = 0; for (let j = 0; j < 20; j++) { if (dp[i][j]) { ans += 1 << j; } } a[i] = ans; } return a; } // Example usage let N = 3; let Q = 2; let U = [[1, 2, 1], [3, 3, 2]]; let ans = updateQuery(N, Q, U); console.log(ans.join( " " )); // Outputs: 1 1 2 |
1 1 2
Time Complexity: O(N)
Auxiliary Space: O(N)
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!