Open In App

Count of odd and even parity elements in subarray using MO’s algorithm

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr consisting of N elements and Q queries represented by L and R denoting a range, the task is to print the count of odd and even parity elements in the subarray [L, R].

Examples:

Input: arr[]=[5, 2, 3, 1, 4, 8, 10] Q=2 1 3 0 4
Output: 2 1 3 2
Explanation: In query 1, odd parity elements in subarray [1:3] are 2 and 1 and the even parity element is 3. In query 2, odd parity elements in subarray [0:4] are 2, 1, and 4 and even parity elements are 5 and 3.

Input: arr[] = { 13, 17, 12, 10, 18, 19, 15, 7, 9, 6 } Q=3 1 5 0 7 2 9
Output: 1 4 3 5 2 6
Explanation: In query 1, the odd parity element in subarray [1:4] is 19 and even parity elements are 17,12,10 and 18. In query 2, odd parity elements in subarray [0:7] are 13, 19, and 7 and even parity elements are 17,12,10,18 and 15. In query 3, odd parity elements in subarray [2:6] are 19 and 7 and even parity elements are 12,10,18, 15, 9, and 6.

Approach:

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

  • Sort all queries so 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)
  • Process all queries one by one and increase the count of odd parity elements and store the result in the structure.
  • 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 count_oddP.

Removing elements()

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

Below is the implementation of the above approach:

C++




// C++ program to count odd and
// even parity elements in subarray
// using MO's algorithm
 
#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;
    // Ending index
    int R;
    // Index of query
    int 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;
 
        // 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++;
        }
 
        q[i].odd = count_oddP;
        q[i].even = R - L + 1 - 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, 12 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    Query q[] = { { 1, 3, 0, 0, 0 },
                  { 0, 4, 1, 0, 0 },
                  { 4, 7, 2, 0, 0 } };
 
    int m = sizeof(q) / sizeof(q[0]);
 
    queryResults(arr, n, q, m);
 
    printResults(q, m);
 
    return 0;
}


Java




import java.util.Arrays;
 
// Class to represent a query range
class Query {
    // Starting index
    int L;
    // Ending index
    int R;
    // Index of query
    int index;
    // Count of odd parity elements
    int odd;
    // Count of even parity elements
    int even;
 
    Query(int L, int R, int index)
    {
        this.L = L;
        this.R = R;
        this.index = index;
        this.odd = 0;
        this.even = 0;
    }
}
 
public class GFG {
    // Variable to represent block size.
    // This is made global so compare()
    // can use it.
    static int block;
 
    // To store the count of odd parity elements
    static int count_oddP;
 
    // Function to Add elements
    // of the current range
    static void add(int currL, int[] a)
    {
        if (Integer.bitCount(a[currL]) % 2 != 0)
            count_oddP++;
    }
 
    // Function to remove elements
    // of the previous range
    static void remove(int currR, int[] a)
    {
        if (Integer.bitCount(a[currR]) % 2 != 0)
            count_oddP--;
    }
 
    // Function to generate the result of queries
    static void queryResults(int[] a, int n, Query[] q,
                             int m)
    {
        // Initialize the number of odd parity elements to 0
        count_oddP = 0;
 
        // Find the block size
        block = (int)Math.sqrt(n);
 
        // Sort all queries so that queries of the same
        // blocks are arranged together.
        Arrays.sort(q, (x, y) -> {
            if (x.L / block != y.L / block)
                return x.L / block - y.L / block;
            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 the current range
            int L = q[i].L, R = q[i].R;
 
            // Add elements of the current range
            while (currR <= R) {
                add(currR, a);
                currR++;
            }
            while (currL > L) {
                add(currL - 1, a);
                currL--;
            }
 
            // Remove element of the previous range
            while (currR > R + 1) {
                remove(currR - 1, a);
                currR--;
            }
            while (currL < L) {
                remove(currL, a);
                currL++;
            }
 
            q[i].odd = count_oddP;
            q[i].even = R - L + 1 - count_oddP;
        }
    }
 
    // Function to display the results of queries in their
    // initial order
    static void printResults(Query[] q, int m)
    {
        Arrays.sort(q, (x, y) -> 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, 12 };
        int n = arr.length;
 
        Query[] q
            = { new Query(1, 3, 0), new Query(0, 4, 1),
                new Query(4, 7, 2) };
 
        int m = q.length;
 
        queryResults(arr, n, q, m);
 
        printResults(q, m);
    }
}


Python




import math
 
# Structure to represent a query range
class Query:
    def __init__(self, L, R, index, odd, even):
        self.L = L
        self.R = R
        self.index = index
        self.odd = odd
        self.even = even
 
# 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):
    # 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 the same order as input
def compare1(x, y):
    return x.index < y.index
 
# Function to Add elements
# of the current range
def add(currL, a):
    global count_oddP
    # __builtin_parity(x) returns True (1)
    # if the number has odd parity else
    # it returns False (0) for even parity.
    if bin(a[currL]).count('1') % 2 == 1:
        count_oddP += 1
 
# Function to remove elements
# of the previous range
def remove(currR, a):
    global count_oddP
    # __builtin_parity(x) returns True (1)
    # if the number has odd parity else
    # it returns False (0) for even parity.
    if bin(a[currR]).count('1') % 2 == 1:
        count_oddP -= 1
 
# Function to generate the result of queries
def queryResults(a, n, q, m):
    global block, count_oddP
    # Initialize number of odd parity
    # elements to 0
    count_oddP = 0
 
    # Find block size
    block = int(math.sqrt(n))
 
    # Sort all queries so that queries of
    # the same blocks are arranged together.
    q.sort(key=lambda x: (x.L // block, x.R))
 
    # Initialize current L, current R, and
    # current result
    currL, currR = 0, 0
 
    for i in range(m):
        # L and R values of the current range
        L, R = q[i].L, q[i].R
 
        # Add Elements of the current range
        while currR <= R:
            add(currR, a)
            currR += 1
        while currL > L:
            add(currL - 1, a)
            currL -= 1
 
        # Remove element of the previous range
        while currR > R + 1:
            remove(currR - 1, a)
            currR -= 1
        while currL < L:
            remove(currL, a)
            currL += 1
 
        q[i].odd = count_oddP
        q[i].even = R - L + 1 - count_oddP
 
# 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, 12]
    n = len(arr)
 
    q = [Query(1, 3, 0, 0, 0),
         Query(0, 4, 1, 0, 0),
         Query(4, 7, 2, 0, 0)]
 
    m = len(q)
 
    queryResults(arr, n, q, m)
 
    printResults(q, m)


C#




using System;
 
class Query
{
    public int L; // Starting index
    public int R; // Ending index
    public int index; // Index of query
    public int odd; // Count of odd parity elements
    public int even; // Count of even parity elements
}
 
class Program
{
    static int block;
    static int count_oddP;
 
    static void Add(int currL, int[] a)
    {
        if (Convert.ToString(a[currL], 2).Replace("0", "").Length % 2 == 1)
            count_oddP++;
    }
 
    static void Remove(int currR, int[] a)
    {
        if (Convert.ToString(a[currR], 2).Replace("0", "").Length % 2 == 1)
            count_oddP--;
    }
 
    static void QueryResults(int[] a, int n, Query[] q, int m)
    {
        count_oddP = 0;
        block = (int)Math.Sqrt(n);
        Array.Sort(q, (x, y) => {
            if (x.L / block != y.L / block)
                return x.L / block - y.L / block;
            return x.R - y.R;
        });
 
        int currL = 0, currR = 0;
 
        for (int i = 0; i < m; i++)
        {
            int L = q[i].L, R = q[i].R;
 
            while (currR <= R)
            {
                Add(currR, a);
                currR++;
            }
            while (currL > L)
            {
                Add(currL - 1, a);
                currL--;
            }
 
            while (currR > R + 1)
            {
                Remove(currR - 1, a);
                currR--;
            }
            while (currL < L)
            {
                Remove(currL, a);
                currL++;
            }
 
            q[i].odd = count_oddP;
            q[i].even = R - L + 1 - count_oddP;
        }
    }
 
    static void PrintResults(Query[] q, int m)
    {
        Array.Sort(q, (x, y) => x.index - y.index);
        for (int i = 0; i < m; i++)
        {
            Console.WriteLine(q[i].odd + " " + q[i].even);
        }
    }
 
    static void Main(string[] args)
    {
        int[] arr = { 5, 2, 3, 1, 4, 8, 10, 12 };
        int n = arr.Length;
 
        Query[] q = { new Query { L = 1, R = 3, index = 0 },
                    new Query { L = 0, R = 4, index = 1 },
                    new Query { L = 4, R = 7, index = 2 } };
 
        int m = q.Length;
 
        QueryResults(arr, n, q, m);
 
        PrintResults(q, m);
    }
}


Javascript




class Query {
    constructor(L, R, index, odd, even) {
        this.L = L;
        this.R = R;
        this.index = index;
        this.odd = odd;
        this.even = even;
    }
}
 
let block;
let count_oddP;
 
function add(currL, a) {
    if (countSetBits(a[currL]) % 2 === 1)
        count_oddP++;
}
 
function remove(currR, a) {
    if (countSetBits(a[currR]) % 2 === 1)
        count_oddP--;
}
 
function countSetBits(num) {
    let count = 0;
    while (num) {
        count += num & 1;
        num >>= 1;
    }
    return count;
}
 
function queryResults(a, n, q, m) {
    count_oddP = 0;
    block = Math.sqrt(n);
    q.sort((x, y) => {
        if (x.L / block !== y.L / block)
            return x.L / block - y.L / block;
        return x.R - y.R;
    });
 
    let currL = 0, currR = 0;
 
    for (let i = 0; i < m; i++) {
        const L = q[i].L, R = q[i].R;
 
        while (currR <= R) {
            add(currR, a);
            currR++;
        }
        while (currL > L) {
            add(currL - 1, a);
            currL--;
        }
 
        while (currR > R + 1) {
            remove(currR - 1, a);
            currR--;
        }
        while (currL < L) {
            remove(currL, a);
            currL++;
        }
 
        q[i].odd = count_oddP;
        q[i].even = R - L + 1 - count_oddP;
    }
}
 
function printResults(q) {
    q.sort((x, y) => x.index - y.index);
    for (let i = 0; i < q.length; i++) {
        console.log(q[i].odd + " " + q[i].even);
    }
}
 
const arr = [5, 2, 3, 1, 4, 8, 10, 12];
const n = arr.length;
 
const q = [
    new Query(1, 3, 0, 0, 0),
    new Query(0, 4, 1, 0, 0),
    new Query(4, 7, 2, 0, 0)
];
 
const m = q.length;
 
queryResults(arr, n, q, m);
printResults(q);


Output

2 1
3 2
2 2

Time Complexity: O(Q × √n)
Auxiliary Space: O(n + m), where n is the size of the input array, and m is the number of queries.



Last Updated : 10 Jan, 2024
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads