Given an array A[] of length N, where N is an even number, the task is to answer Q independent queries where each query consists of a positive integer K representing the number of circular shifts performed on the array and find the sum of elements by performing Bitwise OR operation on the divided array.
Note: Each query begins with the original array.
Examples:
Input: A[] = {12, 23, 4, 21, 22, 76}, Q = 1, K = 2
Output: 117
Explanation:
Since K is 2, modified array A[]={22, 76, 12, 23, 4, 21}.
Bitwise OR of first half of array = (22 | 76 | 12) = 94
Bitwise OR of second half of array = (21 | 23 | 4) = 23
Sum of OR values is 94 + 23 = 117
Input: A[] = {7, 44, 19, 86, 65, 39, 75, 101}, Q = 1, K = 4
Output: 238
Since K is 4, modified array A[]={65, 39, 75, 101, 7, 44, 19, 86}.
Bitwise OR of first half of array = 111
Bitwise OR of second half of array = 127
Sum of OR values is 111 + 127 = 238
Naive Approach:
To solve the problem mentioned above the simplest approach is to shift each element of the array by K % (N / 2) and then traverse the array to calculate the OR of the two halves for every query. But this method is not efficient and hence can be optimized further.
Efficient Approach:
To optimize the above mentioned approach we can take the help of Segment Tree data structure.
Observation:
- We can observe that after exactly N / 2 right circular shifts the two halves of the array become the same as in the original array. This effectively reduces the number of rotations to K % (N / 2).
- Performing a right circular shift is basically shifting the last element of the array to the front. So for any positive integer X performing X right circular shifts is equal to shifting the last X elements of the array to the front.
Following are the steps to solve the problem :
- Construct a segment tree for the original array A[] and assign a variable let’s say i = K % (N / 2).
- Then for each query we use the segment tree of find the bitwise OR; that is Bitwise OR of i elements from the end OR bitwise OR of the first (N / 2) – i – 1 elements.
- Then calculate the bitwise OR of elements in range [(N / 2) – i, N – i – 1].
- Add the two results to get the answer for the ith query.
Below is the implementation of the above approach:
C++
// C++ Program to find Bitwise OR of two // equal halves of an array after performing // K right circular shifts #include <bits/stdc++.h> const int MAX = 100005; using namespace std; // Array for storing // the segment tree int seg[4 * MAX]; // Function to build the segment tree void build( int node, int l, int r, int a[]) { if (l == r) seg[node] = a[l]; else { int mid = (l + r) / 2; build(2 * node, l, mid, a); build(2 * node + 1, mid + 1, r, a); seg[node] = (seg[2 * node] | seg[2 * node + 1]); } } // Function to return the OR // of elements in the range [l, r] int query( int node, int l, int r, int start, int end, int a[]) { // Check for out of bound condition if (l > end or r < start) return 0; if (start <= l and r <= end) return seg[node]; // Find middle of the range int mid = (l + r) / 2; // Recurse for all the elements in array return ((query(2 * node, l, mid, start, end, a)) | (query(2 * node + 1, mid + 1, r, start, end, a))); } // Function to find the OR sum void orsum( int a[], int n, int q, int k[]) { // Function to build the segment Tree build(1, 0, n - 1, a); // Loop to handle q queries for ( int j = 0; j < q; j++) { // Effective number of // right circular shifts int i = k[j] % (n / 2); // Calculating the OR of // the two halves of the // array from the segment tree // OR of second half of the // array [n/2-i, n-1-i] int sec = query(1, 0, n - 1, n / 2 - i, n - i - 1, a); // OR of first half of the array // [n-i, n-1]OR[0, n/2-1-i] int first = (query(1, 0, n - 1, 0, n / 2 - 1 - i, a) | query(1, 0, n - 1, n - i, n - 1, a)); int temp = sec + first; // Print final answer to the query cout << temp << endl; } } // Driver Code int main() { int a[] = { 7, 44, 19, 86, 65, 39, 75, 101 }; int n = sizeof (a) / sizeof (a[0]); int q = 2; int k[q] = { 4, 2 }; orsum(a, n, q, k); return 0; } |
Java
// Java program to find Bitwise OR of two // equal halves of an array after performing // K right circular shifts import java.util.*; class GFG{ static int MAX = 100005 ; // Array for storing // the segment tree static int []seg = new int [ 4 * MAX]; // Function to build the segment tree static void build( int node, int l, int r, int a[]) { if (l == r) seg[node] = a[l]; else { int mid = (l + r) / 2 ; build( 2 * node, l, mid, a); build( 2 * node + 1 , mid + 1 , r, a); seg[node] = (seg[ 2 * node] | seg[ 2 * node + 1 ]); } } // Function to return the OR // of elements in the range [l, r] static int query( int node, int l, int r, int start, int end, int a[]) { // Check for out of bound condition if (l > end || r < start) return 0 ; if (start <= l && r <= end) return seg[node]; // Find middle of the range int mid = (l + r) / 2 ; // Recurse for all the elements in array return ((query( 2 * node, l, mid, start, end, a)) | (query( 2 * node + 1 , mid + 1 , r, start, end, a))); } // Function to find the OR sum static void orsum( int a[], int n, int q, int k[]) { // Function to build the segment Tree build( 1 , 0 , n - 1 , a); // Loop to handle q queries for ( int j = 0 ; j < q; j++) { // Effective number of // right circular shifts int i = k[j] % (n / 2 ); // Calculating the OR of // the two halves of the // array from the segment tree // OR of second half of the // array [n/2-i, n-1-i] int sec = query( 1 , 0 , n - 1 , n / 2 - i, n - i - 1 , a); // OR of first half of the array // [n-i, n-1]OR[0, n/2-1-i] int first = (query( 1 , 0 , n - 1 , 0 , n / 2 - 1 - i, a) | query( 1 , 0 , n - 1 , n - i, n - 1 , a)); int temp = sec + first; // Print final answer to the query System.out.print(temp + "\n" ); } } // Driver Code public static void main(String[] args) { int a[] = { 7 , 44 , 19 , 86 , 65 , 39 , 75 , 101 }; int n = a.length; int q = 2 ; int k[] = { 4 , 2 }; orsum(a, n, q, k); } } // This code is contributed by 29AjayKumar |
Python3
# Python3 program to find Bitwise OR of two # equal halves of an array after performing # K right circular shifts MAX = 100005 # Array for storing # the segment tree seg = [ 0 ] * ( 4 * MAX ) # Function to build the segment tree def build(node, l, r, a): if (l = = r): seg[node] = a[l] else : mid = (l + r) / / 2 build( 2 * node, l, mid, a) build( 2 * node + 1 , mid + 1 , r, a) seg[node] = (seg[ 2 * node] | seg[ 2 * node + 1 ]) # Function to return the OR # of elements in the range [l, r] def query(node, l, r, start, end, a): # Check for out of bound condition if (l > end or r < start): return 0 if (start < = l and r < = end): return seg[node] # Find middle of the range mid = (l + r) / / 2 # Recurse for all the elements in array return ((query( 2 * node, l, mid, start, end, a)) | (query( 2 * node + 1 , mid + 1 , r, start, end, a))) # Function to find the OR sum def orsum(a, n, q, k): # Function to build the segment Tree build( 1 , 0 , n - 1 , a) # Loop to handle q queries for j in range (q): # Effective number of # right circular shifts i = k[j] % (n / / 2 ) # Calculating the OR of # the two halves of the # array from the segment tree # OR of second half of the # array [n/2-i, n-1-i] sec = query( 1 , 0 , n - 1 , n / / 2 - i, n - i - 1 , a) # OR of first half of the array # [n-i, n-1]OR[0, n/2-1-i] first = (query( 1 , 0 , n - 1 , 0 , n / / 2 - 1 - i, a) | query( 1 , 0 , n - 1 , n - i, n - 1 , a)) temp = sec + first # Print final answer to the query print (temp) # Driver Code if __name__ = = "__main__" : a = [ 7 , 44 , 19 , 86 , 65 , 39 , 75 , 101 ] n = len (a) q = 2 k = [ 4 , 2 ] orsum(a, n, q, k) # This code is contributed by chitranayal |
C#
// C# program to find Bitwise OR of two // equal halves of an array after performing // K right circular shifts using System; class GFG{ static int MAX = 100005; // Array for storing // the segment tree static int []seg = new int [4 * MAX]; // Function to build the segment tree static void build( int node, int l, int r, int []a) { if (l == r) seg[node] = a[l]; else { int mid = (l + r) / 2; build(2 * node, l, mid, a); build(2 * node + 1, mid + 1, r, a); seg[node] = (seg[2 * node] | seg[2 * node + 1]); } } // Function to return the OR // of elements in the range [l, r] static int query( int node, int l, int r, int start, int end, int []a) { // Check for out of bound condition if (l > end || r < start) return 0; if (start <= l && r <= end) return seg[node]; // Find middle of the range int mid = (l + r) / 2; // Recurse for all the elements in array return ((query(2 * node, l, mid, start, end, a)) | (query(2 * node + 1, mid + 1, r, start, end, a))); } // Function to find the OR sum static void orsum( int []a, int n, int q, int []k) { // Function to build the segment Tree build(1, 0, n - 1, a); // Loop to handle q queries for ( int j = 0; j < q; j++) { // Effective number of // right circular shifts int i = k[j] % (n / 2); // Calculating the OR of // the two halves of the // array from the segment tree // OR of second half of the // array [n/2-i, n-1-i] int sec = query(1, 0, n - 1, n / 2 - i, n - i - 1, a); // OR of first half of the array // [n-i, n-1]OR[0, n/2-1-i] int first = (query(1, 0, n - 1, 0, n / 2 - 1 - i, a) | query(1, 0, n - 1, n - i, n - 1, a)); int temp = sec + first; // Print readonly answer to the query Console.Write(temp + "\n" ); } } // Driver Code public static void Main(String[] args) { int []a = { 7, 44, 19, 86, 65, 39, 75, 101 }; int n = a.Length; int q = 2; int []k = { 4, 2 }; orsum(a, n, q, k); } } // This code is contributed by 29AjayKumar |
Javascript
<script> // javascript program to find Bitwise OR of two // equal halves of an array after performing // K right circular shifts const MAX = 100005; // Array for storing // the segment tree var seg = Array(4 * MAX).fill(0); // Function to build the segment tree function build(node , l , r , a) { if (l == r) seg[node] = a[l]; else { var mid = parseInt((l + r) / 2); build(2 * node, l, mid, a); build(2 * node + 1, mid + 1, r, a); seg[node] = (seg[2 * node] | seg[2 * node + 1]); } } // Function to return the OR // of elements in the range [l, r] function query(node , l , r , start , end , a) { // Check for out of bound condition if (l > end || r < start) return 0; if (start <= l && r <= end) return seg[node]; // Find middle of the range var mid = parseInt((l + r) / 2); // Recurse for all the elements in array return ((query(2 * node, l, mid, start, end, a)) | (query(2 * node + 1, mid + 1, r, start, end, a))); } // Function to find the OR sum function orsum(a , n , q , k) { // Function to build the segment Tree build(1, 0, n - 1, a); // Loop to handle q queries for (j = 0; j < q; j++) { // Effective number of // right circular shifts var i = k[j] % (n / 2); // Calculating the OR of // the two halves of the // array from the segment tree // OR of second half of the // array [n/2-i, n-1-i] var sec = query(1, 0, n - 1, n / 2 - i, n - i - 1, a); // OR of first half of the array // [n-i, n-1]OR[0, n/2-1-i] var first = (query(1, 0, n - 1, 0, n / 2 - 1 - i, a) | query(1, 0, n - 1, n - i, n - 1, a)); var temp = sec + first; // Print final answer to the query document.write(temp + "<br/>" ); } } // Driver Code var a = [ 7, 44, 19, 86, 65, 39, 75, 101 ]; var n = a.length; var q = 2; var k = [ 4, 2 ]; orsum(a, n, q, k); // This code is contributed by Rajput-Ji. </script> |
238 230
Time Complexity: O(N + Q*log(N))
Auxiliary Space: O(4*MAX)
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!