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

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.

  1. 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.
  2. Count the odd parity elements and then calculate the even parity elements as (R - L + 1- odd parity elements)
  3. 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.
  4. 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].
  5. 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:

    CPP

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

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

    chevron_right

    
    

    Output:

    4 2
    1 3
    2 1
    

    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.