Open In App

Query to count odd and even parity elements in subarray after XOR with K

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] consisting of N elements and Q queries represented by L, R, and K. The task is to print the count of odd and even parity elements in the subarray [L, R] after Bitwise-XOR with K.

Examples:  

Input: arr[] = {5, 2, 3, 1, 4, 8, 10} 
query[] = {{0, 5, 3}, {1, 4, 8}, {4, 6, 10}} 
Output: 
4 2 
1 3 
2 1 
Explanation: 
In query 1, the odd and even parity elements in subarray [0:5] are [2, 1, 4, 8] and [5, 3]. Now after XOR with K = 3, the number of odd and even parity elements are 4 and 2 respectively. 
In query 2, the odd and even parity elements in subarray [1:4] are [2, 1, 4] and [3]. Now after XOR with K = 8, the number of odd and even parity elements are 1 and 3 respectively. 
In query 3, the odd and even parity elements in subarray [4:6] are [4, 8] and [10]. Now after XOR with K = 10, the number of odd and even parity elements are 2 and 1 respectively. 

Approach: The idea is to use MO’s algorithm to pre-process all queries so that result of one query can be used in the next query. 

  • Sort all queries in a way that queries with L values from 0 to ?n – 1 are put together, followed by queries from ?n to 2 ×?n – 1, and so on. All queries within a block are sorted in increasing order of R values.
  • Count the odd parity elements and then calculate the even parity elements as

(R - L + 1- odd parity elements)

  • Observation after XOR with odd and even parity elements: 
    • XOR of two odd parity elements is an even parity element.
    • XOR of two even parity elements is an even parity element.
    • XOR of one even parity element and another odd parity element is an odd parity element and vice-versa.
  • Process all queries one by one and increase the count of odd parity elements and now we will check the parity of K. If K has an even parity then the count of odd and even parity remains the same else we swap them. 
    • Let count_oddP store the count of odd parity elements in previous query.
    • Remove extra elements of previous query and add new elements for the current query. For example, if previous query was [0, 8] and the current query is [3, 9], then remove the elements arr[0], arr[1] and arr[2] and add arr[9].
  • In order to display the results, sort the queries in the order they were provided.


Adding elements 

  • If the current element has odd parity then increase the count of odd parity.

Removing elements 

  • If the current element has odd parity then decrease the count of odd parity.

Below is the implementation of the above approach: 

C++

// C++ program to count odd and
// even parity elements in subarray
// after XOR with K
 
#include <bits/stdc++.h>
using namespace std;
 
#define MAX 100000
 
// Variable to represent block size.
// This is made global so compare()
// of sort can use it
int block;
 
// Structure to represent
// a query range
struct Query {
    // Starting index
    int L, R, K, index;
 
    // Count of odd
    // parity elements
    int odd;
 
    // Count of even
    // parity elements
    int even;
};
 
// To store the count of
// odd parity elements
int count_oddP;
 
// Function used to sort all queries so that
// all queries of the same block are arranged
// together and within a block, queries are
// sorted in increasing order of R values.
bool compare(Query x, Query y)
{
    // Different blocks, sort by block.
    if (x.L / block != y.L / block)
        return x.L / block < y.L / block;
 
    // Same block, sort by R value
    return x.R < y.R;
}
 
// Function used to sort all queries
// in order of their index value so
// that results of queries can be
// printed in same order as of input
bool compare1(Query x, Query y)
{
    return x.index < y.index;
}
 
// Function to Add elements
// of current range
void add(int currL, int a[])
{
    // _builtin_parity(x)returns true(1)
    // if the number has odd parity else
    // it returns false(0) for even parity.
    if (__builtin_parity(a[currL]))
        count_oddP++;
}
 
// Function to remove elements
// of previous range
void remove(int currR, int a[])
{
    // _builtin_parity(x)returns true(1)
    // if the number has odd parity else
    // it returns false(0) for even parity.
    if (__builtin_parity(a[currR]))
        count_oddP--;
}
 
// Function to generate the result of queries
void queryResults(int a[], int n, Query q[],
                  int m)
{
 
    // Initialize number of odd parity
    // elements to 0
    count_oddP = 0;
 
    // Find block size
    block = (int)sqrt(n);
 
    // Sort all queries so that queries of
    // same blocks are arranged together.
    sort(q, q + m, compare);
 
    // Initialize current L, current R and
    // current result
    int currL = 0, currR = 0;
 
    for (int i = 0; i < m; i++) {
 
        // L and R values of current range
        int L = q[i].L,
            R = q[i].R,
            k = q[i].K;
 
        // Add Elements of current range
        while (currR <= R) {
            add(currR, a);
            currR++;
        }
        while (currL > L) {
            add(currL - 1, a);
            currL--;
        }
 
        // Remove element of previous range
        while (currR > R + 1)
 
        {
            remove(currR - 1, a);
            currR--;
        }
        while (currL < L) {
            remove(currL, a);
            currL++;
        }
 
        // If parity of K is even
        // then the count of odd
        // and even parity remains
        // the same
        if (!__builtin_parity(k)) {
            q[i].odd = count_oddP;
            q[i].even
                = R - L + 1 - count_oddP;
        }
        // If parity of K is odd
        // we swap the count of
        // odd and even parity
        // elements
        else {
            q[i].odd
                = R - L + 1 - count_oddP;
            q[i].even = count_oddP;
        }
    }
}
 
// Function to display the results of
// queries in their initial order
void printResults(Query q[], int m)
{
    sort(q, q + m, compare1);
    for (int i = 0; i < m; i++) {
        cout << q[i].odd << " "
             << q[i].even << endl;
    }
}
 
// Driver Code
int main()
{
 
    int arr[] = { 5, 2, 3, 1, 4, 8, 10 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    Query q[] = { { 0, 5, 3, 0, 0, 0 },
                  { 1, 4, 8, 1, 0, 0 },
                  { 4, 6, 10, 2, 0, 0 } };
 
    int m = sizeof(q) / sizeof(q[0]);
 
    queryResults(arr, n, q, m);
 
    printResults(q, m);
 
    return 0;
}

                    

Java

// Java program to count odd and
// even parity elements in subarray
// after XOR with K
import java.io.*;
import java.util.*;
 
// Class to represent
// a query range
class Query
{
    int L, R, K, index;
 
    // Count of odd
    // parity elements
    int odd;
 
    // Count of even
    // parity elements
    int even;
 
    Query(int L, int R, int K,
          int index, int odd, int even)
    {
        this.L = L;
        this.R = R;
        this.K = K;
        this.index = index;
        this.odd = odd;
        this.even = even;
    }
}
 
class GFG{
 
// Variable to represent block size.
static int block;
 
// To store the count of
// odd parity elements
static int count_oddP;
 
// Function to Add elements
// of current range
static void add(int currL, int a[])
{
     
    // _builtin_parity(x)returns true
    // if the number has odd parity else
    // it returns false for even parity.
    if (__builtin_parity(a[currL]))
        count_oddP++;
}
 
// Function to remove elements
// of previous range
static void remove(int currR, int a[])
{
     
    // _builtin_parity(x)returns true
    // if the number has odd parity else
    // it returns false for even parity.
    if (__builtin_parity(a[currR]))
        count_oddP--;
}
 
// Function to generate the result of queries
static void queryResults(int a[], int n, Query q[],
                         int m)
{
     
    // Initialize number of odd parity
    // elements to 0
    count_oddP = 0;
 
    // Find block size
    block = (int)(Math.sqrt(n));
 
    // sort all queries so that all queries
    // of the same block are arranged together
    // and within a block, queries are sorted
    // in increasing order of R values.
    Arrays.sort(q, (Query x, Query y) ->
    {
         
        // Different blocks, sort by block.
        if (x.L / block != y.L / block)
            return x.L / block - y.L / block;
 
        // Same block, sort by R value
        return x.R - y.R;
    });
 
    // Initialize current L, current R and
    // current result
    int currL = 0, currR = 0;
 
    for(int i = 0; i < m; i++)
    {
         
        // L and R values of current range
        int L = q[i].L, R = q[i].R, k = q[i].K;
 
        // Add Elements of current range
        while (currR <= R)
        {
            add(currR, a);
            currR++;
        }
        while (currL > L)
        {
            add(currL - 1, a);
            currL--;
        }
 
        // Remove element of previous range
        while (currR > R + 1)
        {
            remove(currR - 1, a);
            currR--;
        }
        while (currL < L)
        {
            remove(currL, a);
            currL++;
        }
 
        // If parity of K is even
        // then the count of odd
        // and even parity remains
        // the same
        if (!__builtin_parity(k))
        {
            q[i].odd = count_oddP;
            q[i].even = R - L + 1 - count_oddP;
        }
         
        // If parity of K is odd
        // we swap the count of
        // odd and even parity
        // elements
        else
        {
            q[i].odd = R - L + 1 - count_oddP;
            q[i].even = count_oddP;
        }
    }
}
 
static boolean __builtin_parity(int K)
{
    return (Integer.bitCount(K) % 2) == 1;
}
 
// Function to display the results of
// queries in their initial order
static void printResults(Query q[], int m)
{
    Arrays.sort(q, (Query x, Query y) ->
 
                // sort all queries
                // in order of their
                // index value so that results
                // of queries can be printed
                // in same order as of input);
                x.index - y.index);
 
    for(int i = 0; i < m; i++)
    {
        System.out.println(q[i].odd + " " +
                           q[i].even);
    }
}
 
// Driver Code
public static void main(String[] args)
{
    int arr[] = { 5, 2, 3, 1, 4, 8, 10 };
    int n = arr.length;
 
    Query q[] = new Query[3];
    q[0] = new Query(0, 5, 3, 0, 0, 0);
    q[1] = new Query(1, 4, 8, 1, 0, 0);
    q[2] = new Query(4, 6, 10, 2, 0, 0);
 
    int m = q.length;
 
    queryResults(arr, n, q, m);
 
    printResults(q, m);
}
}
 
// This code is contributed by jithin

                    

Python

import math
from functools import cmp_to_key
 
# Class to represent
# a query range
class Query:
    def __init__(self, L, R, K, index, odd, even):
        self.L = L
        self.R = R
        self.K = K
        self.index = index
        self.odd = odd
        self.even = even
 
 
# Variable to represent block size.
block = 0
 
# To store the count of
# odd parity elements
count_oddP = 0
 
# Function used to sort all queries so that
# all queries of the same block are arranged
# together and within a block, queries are
# sorted in increasing order of R values.
def compare(x, y):
    if x.L // block != y.L // block:
        return x.L // block - y.L // block
    return x.R - y.R
 
# Function to Add elements
# of current range
def add(currL, a):
    # Check if the number has odd parity
    global count_oddP
    if __builtin_parity(a[currL]):
        count_oddP += 1
 
# Function to remove elements
# of previous range
def remove(currR, a):
    # Check if the number has odd parity
    global count_oddP
    if __builtin_parity(a[currR]):
        count_oddP -= 1
 
# Function to generate the result of queries
def queryResults(a, n, q, m):
    global count_oddP
    count_oddP = 0
 
    # Find block size
    global block
    block = int(math.sqrt(n))
 
    # sort all queries so that all queries
    # of the same block are arranged together
    # and within a block, queries are sorted
    # in increasing order of R values.
    q.sort(key=cmp_to_key(compare))
 
    # Initialize current L, current R and
    # current result
    currL = 0
    currR = 0
 
    for i in range(m):
        L = q[i].L
        R = q[i].R
        k = q[i].K
 
        while currR <= R:
            add(currR, a)
            currR += 1
        while currL > L:
            add(currL - 1, a)
            currL -= 1
 
        while currR > R + 1:
            remove(currR - 1, a)
            currR -= 1
        while currL < L:
            remove(currL, a)
            currL += 1
 
        if not __builtin_parity(k):
            q[i].odd = count_oddP
            q[i].even = R - L + 1 - count_oddP
        else:
            q[i].odd = R - L + 1 - count_oddP
            q[i].even = count_oddP
 
 
def __builtin_parity(K):
    return bin(K).count('1') % 2 == 1
 
# Function to display the results of
# queries in their initial order
def printResults(q, m):
    q.sort(key=lambda x: x.index)
    for i in range(m):
        print(q[i].odd, q[i].even)
 
 
# Driver Code
if __name__ == "__main__":
    arr = [5, 2, 3, 1, 4, 8, 10]
    n = len(arr)
    q = [
        Query(0, 5, 3, 0, 0, 0),
        Query(1, 4, 8, 1, 0, 0),
        Query(4, 6, 10, 2, 0, 0)
    ]
 
    m = len(q)
    queryResults(arr, n, q, m)
    printResults(q, m)
 
# This code is contributed by Samim Hossain Mondal.

                    

C#

// C# program to count odd and
// even parity elements in subarray
// after XOR with K
using System;
using System.Linq;
 
// Class to represent
// a query range
class Query
{
  public int L, R, K, index;
 
  // Count of odd
  // parity elements
  public int odd;
 
  // Count of even
  // parity elements
  public int even;
 
  public Query(int L, int R, int K, int index, int odd, int even)
  {
    this.L = L;
    this.R = R;
    this.K = K;
    this.index = index;
    this.odd = odd;
    this.even = even;
  }
}
 
class GFG
{
 
  // Variable to represent block size.
  static int block;
 
  // To store the count of
  // odd parity elements
  static int count_oddP;
 
  // Function to Add elements
  // of current range
  static void Add(int currL, int[] a)
  {
 
    // _builtin_parity(x)returns true
    // if the number has odd parity else
    // it returns false for even parity.
    if (IsOdd(a[currL]))
      count_oddP++;
  }
 
  // Function to remove elements
  // of previous range
  static void Remove(int currR, int[] a)
  {
 
    // _builtin_parity(x)returns true
    // if the number has odd parity else
    // it returns false for even parity.
    if (IsOdd(a[currR]))
      count_oddP--;
  }
 
  // Function to generate the result of queries
  static void QueryResults(int[] a, int n, Query[] q, int m)
  {
 
    // Initialize number of odd parity
    // elements to 0
    count_oddP = 0;
 
    // Find block size
    block = (int)(Math.Sqrt(n));
 
 
    // sort all queries so that all queries
    // of the same block are arranged together
    // and within a block, queries are sorted
    // in increasing order of R values.
    Array.Sort(q, (x, y) =>
               {
 
                 // Different blocks, sort by block.
                 if (x.L / block != y.L / block)
                   return x.L / block - y.L / block;
 
                 // Same block, sort by R value
                 return x.R - y.R;
               });
 
    // Initialize current L, current R and
    // current result
    int currL = 0, currR = 0;
 
    for (int i = 0; i < m; i++)
    {
 
      // L and R values of current range
      int L = q[i].L, R = q[i].R, k = q[i].K;
 
      // Add Elements of current range
      while (currR <= R)
      {
        Add(currR, a);
        currR++;
      }
 
      while (currL > L)
      {
        Add(currL - 1, a);
        currL--;
      }
 
      // Remove element of previous range
      while (currR > R + 1)
      {
        Remove(currR - 1, a);
        currR--;
      }
 
      while (currL < L)
      {
        Remove(currL, a);
        currL++;
      }
 
 
      // If parity of K is even
      // then the count of odd
      // and even parity remains
      // the same
      if (!IsOdd(k))
      {
        q[i].odd = count_oddP;
        q[i].even = R - L + 1 - count_oddP;
      }
 
 
      // If parity of K is odd
      // we swap the count of
      // odd and even parity
      // elements
      else
      {
        q[i].odd = R - L + 1 - count_oddP;
        q[i].even = count_oddP;
      }
    }
  }
 
  static bool IsOdd(int k)
  {
    return (Convert.ToString(k, 2).Count(c => c == '1') % 2) == 1;
  }
 
 
  // Function to display the results of
  // queries in their initial order
  static void PrintResults(Query[] q, int m)
  {
 
    // sort all queries
    // in order of their
    // index value so that results
    // of queries can be printed
    // in same order as of input);
    Array.Sort(q, (x, y) => x.index - y.index);
 
    for (int i = 0; i < m; i++)
    {
      Console.WriteLine(q[i].odd + " " + q[i].even);
    }
  }
 
  // Driver Code
  static void Main(string[] args)
  {
    int[] arr = { 5, 2, 3, 1, 4, 8, 10 };
    int n = arr.Length;
 
    Query[] q = new Query[3];
    q[0] = new Query(0, 5, 3, 0, 0, 0);
    q[1] = new Query(1, 4, 8, 1, 0, 0);
    q[2] = new Query(4, 6, 10, 2, 0, 0);
 
    int m = q.Length;
 
    QueryResults(arr, n, q, m);
 
    PrintResults(q, m);
  }
}
 
// This code is contributed by shivhack999

                    

Javascript

// Function used to sort all queries so that
// all queries of the same block are arranged
// together and within a block, queries are
// sorted in increasing order of R values.
function compare(x, y)
{
 
    // Different blocks, sort by block.
    if (x.L / block != y.L / block)
        return x.L / block < y.L / block;
 
    // Same block, sort by R value
    return x.R < y.R;
}
 
// Function used to sort all queries
// in order of their index value so
// that results of queries can be
// printed in same order as of input
function compare1(x, y) {
    return x.index < y.index;
}
 
// Function to Add elements
// of current range
function add(currL, a) {
    // _builtin_parity(x)returns true(1)
    // if the number has odd parity else
    // it returns false(0) for even parity.
    if (Number.isInteger(a[currL]))
        count_oddP++;
}
 
// Function to remove elements
// of previous range
function remove(currR, a) {
    // _builtin_parity(x)returns true(1)
    // if the number has odd parity else
    // it returns false(0) for even parity.
    if (Number.isInteger(a[currR]))
        count_oddP--;
}
 
// Function to generate the result of queries
function queryResults(a, n, q, m) {
 
    // Initialize number of odd parity
    // elements to 0
    let count_oddP = 0;
 
    // Find block size
    let block = Math.sqrt(n);
 
    // Sort all queries so that queries of
    // same blocks are arranged together.
    q.sort(compare);
 
    // Initialize current L, current R and
    // current result
    let currL = 0,
        currR = 0;
 
    for (let i = 0; i < m; i++) {
 
        // L and R values of current range
        let L = q[i].L,
            R = q[i].R,
            k = q[i].K;
 
        // Add Elements of current range
        while (currR <= R) {
            add(currR, a);
            currR++;
        }
        while (currL > L) {
            add(currL - 1, a);
            currL--;
        }
 
        // Remove element of previous range
        while (currR > R + 1)
 
        {
            remove(currR - 1, a);
            currR--;
        }
        while (currL < L) {
            remove(currL, a);
            currL++;
        }
 
        // If parity of K is even
        // then the count of odd
        // and even parity remains
        // the same
        if (!Number.isInteger(k)) {
            q[i].odd = count_oddP;
            q[i].even
                = R - L + 1 - count_oddP;
        }
        // If parity of K is odd
        // we swap the count of
        // odd and even parity
        // elements
        else {
            q[i].odd
                = R - L + 1 - count_oddP;
            q[i].even = count_oddP;
        }
    }
}
 
// Function to display the results of
// queries in their initial order
function printResults(q, m) {
    q.sort(compare1);
    for (let i = 0; i < m; i++) {
        console.log(q[i].odd + " " +
            q[i].even);
    }
}
 
// Driver Code
let arr = [5, 2, 3, 1, 4, 8, 10];
let n = arr.length;
 
let q = [{
        L: 0,
        R: 5,
        K: 3,
        index: 0,
        odd: 0,
        even: 0
    },
    {
        L: 1,
        R: 4,
        K: 8,
        index: 1,
        odd: 0,
        even: 0
    },
    {
        L: 4,
        R: 6,
        K: 10,
        index: 2,
        odd: 0,
        even: 0
    }
];
 
let m = q.length;
 
queryResults(arr, n, q, m);
 
printResults(q, m);
 
// This code is contributed by ruchikabaslas.

                    

Output
4 2
1 3
2 1


Time Complexity: O((n + m) * sqrt(n)), where n is the size of the array and m is the number of queries.
Auxiliary Space: O(m)



Last Updated : 01 Nov, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads