📌  相关文章
📜  使用MO算法查询给定范围内的偶数和元素的计数

📅  最后修改于: 2021-05-17 17:59:05             🧑  作者: Mango

给定N个元素的数组arr [] ,任务是回答Q个查询,每个查询都有两个整数LR。对于每个查询,任务是找到数字总和为偶数的子数组arr [L…R]中的元素数量。

例子:

我们已经讨论了这种方法:使用段树查询给定范围内的偶数和元素的计数

方法:(使用MO的算法)
这个想法是预处理所有查询,以便一个查询的结果可以在下一个查询中使用。

  1. 对所有查询进行排序,将L值从0到√n– 1的查询放在一起,然后是从√n到2×√n– 1的查询,依此类推。块中的所有查询均按R值的升序排序。
  2. 一个接一个地处理所有查询,并增加偶数和元素的数量,并将结果存储在结构中。
    • count_even存储上一个查询中的偶数和元素的计数。
    • 删除先前查询的多余元素,并为当前查询添加新元素。例如,如果上一个查询为[0,8],而当前查询为[3,9],则删除元素arr [0],arr [1]和arr [2]并添加arr [9]。
  3. 为了显示结果,请按查询顺序对查询进行排序。

下面的代码是上述方法的实现:

C++
// C++ program to count of even
// digit sum elements in the given
// range using MO's algorithm
 
#include 
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()
    {
         
        // 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()
    {
         
        // 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


输出:
1
2
2



时间复杂度: O(Q x√N)