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: 3
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:1
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.
- 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.
-
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].
- 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++ 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 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 |
# 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 = l # Starting index
self .R = 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) |
// program to count of even // digit sum elements in the given // range using MO's algorithm using System;
using System.Linq;
using System.Collections.Generic;
// Class to represent a query range public class Query
{ public int L { get ; set ; }
public int R { get ; set ; }
public int Index { get ; set ; }
public int Even { get ; set ; }
public Query( int l, int r, int index, int even)
{
L = l;
R = r;
Index = index;
Even = even;
}
} public class GFG
{ static int MAX = 100000;
static int [] arr = new int [] { 5, 2, 3, 1, 4, 8, 10, 12 };
static int n = arr.Length;
// Variable to represent block size.
// This is made here so compare()
// of sort can use it
static int block = ( int )Math.Sqrt(n);
// 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 int Add( int currL, int [] a, int count_even)
{
// If digit sum of a[currL]
// is even then increment
if (DigitSum(a[currL]) % 2 == 0)
{
count_even++;
}
return count_even;
}
// Function to remove elements
// of previous range
static int Remove( int currR, int [] a, int count_even)
{
// If digit sum of a[currL]
// is even then decrement
if (DigitSum(a[currR]) % 2 == 0)
{
count_even--;
}
return 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.
static 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;
}
else
{
// Same block, sort by R value
return x.R - y.R;
}
}
// 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
int count_even = 0;
// Sort all queries so that queries of
// same blocks are arranged together.
q = q.OrderBy(x => x, Comparer<Query>.Create(Compare)).ToArray();
// 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)
{
count_even = Add(currR, a, count_even);
currR++;
}
while (currL > L)
{
count_even = Add(currL - 1, a, count_even);
currL--;
}
// Remove element of previous range
while (currR > R + 1)
{
count_even = Remove(currR - 1, a, count_even);
currR--;
}
while (currL < L)
{
count_even = Remove(currL, a, count_even);
currL++;
}
q[i].Even = count_even;
}
}
// Function to display the results of
// queries in their initial order
static void PrintResults(Query[] q, int m)
{
q = q.OrderBy(x => x.Index).ToArray();
for ( int i = 0; i < m; i++)
{
Console.WriteLine(q[i].Even);
}
}
// Driver Code
public static void Main()
{
Query[] q = new Query[] {
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 shivhach999 |
// Function to find the digit sum for a number function digitSum(num) {
let sum = 0; while (num) {
sum += (num % 10); num = Math.floor(num / 10); } return sum;
} // Function to Add elements of current range function add(currL, a, count_even) {
// If digit sum of a[currL] is even then increment if (digitSum(a[currL]) % 2 === 0) {
count_even++; } return count_even;
} // Function to remove elements of previous range function remove(currR, a, count_even) {
// If digit sum of a[currR] is even then decrement if (digitSum(a[currR]) % 2 === 0) {
count_even--; } return 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. function compare(x, y) {
// Different blocks, sort by block. if (Math.floor(x.L / block) !== Math.floor(y.L / block)) {
return Math.floor(x.L / block) < Math.floor(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 generate the result of queries function queryResults(a, n, q, m) {
// Initialize number of even digit sum to 0 let count_even = 0; // Find block size block = Math.floor(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; // Add Elements of current range while (currR <= R) {
count_even = add(currR, a, count_even);
currR++;
} while (currL > L) {
count_even = add(currL - 1, a, count_even);
currL--;
} // Remove element of previous range while (currR > R + 1) {
count_even = remove(currR - 1, a, count_even);
currR--;
} while (currL < L) {
count_even = remove(currL, a, count_even);
currL++;
} q[i].even = count_even; } } // 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++) {
document.write(q[i].even); } } // Driver Code const arr = [5, 2, 3, 1, 4, 8, 10, 12]; const n = arr.length; const q = [ { L: 1, R: 3, index: 0, even: 0 }, { L: 0, R: 4, index: 1, even: 0 }, { L: 4, R: 7, index: 2, even: 0 }] let m = q.length;
queryResults(arr, n, q, m);
printResults(q, m);
|
1 2 2
Time Complexity: O(Q x ?N)
Auxiliary Space: O(1)