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) = 7
Input: arr[] = {4, 0, 1, 2}, Q[][] = {{1, 3}} 
Output:
 

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++

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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 conSegment 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 conSegment 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

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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 conSegment 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 conSegment 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

chevron_right


Output: 

3 7




 

Time Complexity: O(N*log(sizeof(Q)) 
Auxiliary Space: O(N)

competitive-programming-img




My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.