Skip to content
Related Articles

Related Articles

Queries for count of even digit sum elements in given range using MO’s Algorithm

View Discussion
Improve Article
Save Article
  • Last Updated : 22 Jun, 2022
View Discussion
Improve Article
Save Article

Given an array arr[] of N elements, the task is to answer Q queries each having two integers L and R. For each query, the task is to find the number of elements in the subarray arr[L…R] whose digit sum is even.

Examples:  

Input:arr[] = {7, 3, 19, 13, 5, 4} 
query = { {1, 5}, {0, 1} } 
Output:
Explanation: 
Query 1: Elements 19, 13 and 4 have even digit sum in the subarray: {3, 9, 13, 5, 4}. 
Query 2: No elements have even sum in the subarray: {7, 3}

Input:arr[] = {0, 1, 2, 3, 4, 5, 6, 7} 
query = { 3, 5 } 
Output:

We have already discussed this approach: Queries for the count of even digit sum elements in the given range using Segment Tree

Approach: (Using MO’s Algorithm) 
The idea is 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. Process all queries one by one and increase the count of even digit sum elements and store the result in the structure.
    • Let count_even store the count of even digits sum elements in the 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].
  3. In order to display the results, sort the queries in the order they were provided.

Helper functions:
Adding elements() 

  • If the current element has even digit sum then increase the count of count_even.

Removing elements() 

  • If the current element has even digit sum then decrease the count of count_even.

Below code is the implementation of the above approach: 

C++




// C++ program to count of even
// digit sum elements in the given
// range 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 even
    // even digit sum
    int even;
};
 
// To store the count of
// even digit sum
int count_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.
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 find the digit sum
// for a number
int digitSum(int num)
{
    int sum = 0;
    while (num) {
        sum += (num % 10);
        num /= 10;
    }
 
    return sum;
}
 
// Function to Add elements
// of current range
void add(int currL, int a[])
{
    // If digit sum of a[currL]
    // is even then increment
    if (digitSum(a[currL]) % 2 == 0)
        count_even++;
}
 
// Function to remove elements
// of previous range
void remove(int currR, int a[])
{
 
    // If digit sum of a[currL]
    // is even then decrement
    if (digitSum(a[currR]) % 2 == 0)
        count_even--;
}
 
// Function to generate
// the result of queries
void queryResults(int a[], int n,
                  Query q[], int m)
{
 
    // Initialize number of
    // even digit sum to 0
    count_even = 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].even = count_even;
    }
}
// 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].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, 4, 1, 0 },
                  { 4, 7, 2, 0 } };
 
    int m = sizeof(q) / sizeof(q[0]);
 
    queryResults(arr, n, q, m);
 
    printResults(q, m);
 
    return 0;
}

Java




// Java program to count of even
// digit sum elements in the given
// range using MO's algorithm
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
 
class GFG{
 
static int MAX = 100000;
 
// Variable to represent block size.
// This is made global so compare()
// of sort can use it.
static int block;
 
// Structure to represent a query range
static class Query
{
     
    // Starting index
    int L;
 
    // Ending index
    int R;
 
    // Index of query
    int index;
 
    // Count of even
    // even digit sum
    int even;
 
    public Query(int l, int r,
                 int index, int even)
    {
        this.L = l;
        this.R = r;
        this.index = index;
        this.even = even;
    }
};
 
// To store the count of
// even digit sum
static int count_even;
 
// Function to find the digit sum
// for a number
static int digitSum(int num)
{
    int sum = 0;
    while (num > 0)
    {
        sum += (num % 10);
        num /= 10;
    }
    return sum;
}
 
// Function to Add elements
// of current range
static void add(int currL, int a[])
{
     
    // If digit sum of a[currL]
    // is even then increment
    if (digitSum(a[currL]) % 2 == 0)
        count_even++;
}
 
// Function to remove elements
// of previous range
static void remove(int currR, int a[])
{
     
    // If digit sum of a[currL]
    // is even then decrement
    if (digitSum(a[currR]) % 2 == 0)
        count_even--;
}
 
// Function to generate
// the result of queries
static void queryResults(int a[], int n,
                       Query q[], int m)
{
     
    // Initialize number of
    // even digit sum to 0
    count_even = 0;
 
    // Find block size
    block = (int) Math.sqrt(n);
 
    // Sort all queries so that queries of
    // same blocks are arranged together.
    Collections.sort(Arrays.asList(q),
                     new Comparator<Query>()
    {
         
        // 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.
        public int 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;
        }
    });
 
    // 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].even = count_even;
    }
}
 
// Function to display the results of
// queries in their initial order
static void printResults(Query q[], int m)
{
    Collections.sort(Arrays.asList(q),
             new Comparator<Query>()
    {
         
        // 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
        public int compare(Query x, Query y)
        {
            return x.index - y.index;
        }
    });
    for(int i = 0; i < m; i++)
    {
        System.out.println(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, 0),
                  new Query(0, 4, 1, 0),
                  new Query(4, 7, 2, 0) };
 
    int m = q.length;
 
    queryResults(arr, n, q, m);
 
    printResults(q, m);
}
}
 
// This code is contributed by sanjeev2552

Python3




# Python program to count of even
# digit sum elements in the given
# range using MO's algorithm
import math
import functools
 
MAX = 100000
 
arr = [5, 2, 3, 1, 4, 8, 10, 12]
n = len(arr)
 
# Variable to represent block size.
# This is made here so compare()
# of sort can use it.
block = int(math.sqrt(n))
 
# Class to represent a query range
 
 
class Query:
    def __init__(self, l, r, index, even):
        self.L = # Starting index
        self.R = # Ending index
        self.index = index  # Index of query
        self.even = even  # Count of even digit sum
 
# 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
    else:
        # Same block, sort by R value
        return x.R < y.R
 
# Function to find the digit sum
# for a number
def digitSum(num):
    sum = 0
    while num > 0:
        sum += (num % 10)
        num //= 10
    return sum
 
# Function to Add elements
# of current range
def add(currL, a, count_even):
   
    # If digit sum of a[currL]
    # is even then increment
    if digitSum(a[currL]) % 2 == 0:
        count_even += 1
 
    return count_even
 
# Function to remove elements
# of previous range
def remove(currR, a, count_even):
    # If digit sum of a[currL]
    # is even then decrement
    if digitSum(a[currR]) % 2 == 0:
        count_even -= 1
    return count_even
 
# Function to generate
# the result of queries
def queryResults(a, n, q, m):
 
    # Initialize number of
    # even digit sum to 0
    count_even = 0
 
    # Find block size
    block = int(math.sqrt(n))
 
    # Sort all queries so that queries of
    # same blocks are arranged together.
    q.sort(key=functools.cmp_to_key(compare))
 
    # Initialize current L, current R and
    # current result
    currL = 0
    currR = 0
 
    for i in range(m):
        # L and R values of current range
        L = q[i].L
        R = q[i].R
 
        # Add Elements of current range
        while currR <= R:
            count_even = add(currR, a, count_even)
            currR += 1
 
        while currL > L:
            count_even = add(currL - 1, a, count_even)
            currL -= 1
 
        # Remove element of previous range
        while currR > R + 1:
            count_even = remove(currR - 1, a, count_even)
            currR -= 1
 
        while currL < L:
            count_even = remove(currL, a, count_even)
            currL += 1
 
        q[i].even = count_even
 
# 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].even)
 
# Driver Code
q = [Query(1, 3, 0, 0),
     Query(0, 4, 1, 0),
     Query(4, 7, 2, 0)]
m = len(q)
 
queryResults(arr, n, q, m)
printResults(q, m)
 
# This code is contributed by Tapesh (tapeshdua420)

Output: 

1
2
2

 

Time Complexity: O(Q x √N)
 


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!