Find array sum using Bitwise OR after splitting given array in two halves after K circular shifts

Last Updated : 31 Mar, 2022
Comments
Improve
Suggest changes
Like Article
Like
Report

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>

Output: 
238
230

 

Time Complexity: O(N + Q*log(N))

Auxiliary Space: O(4*MAX)


Next Article

Similar Reads