Open In App

Distinct elements in subarray using Mo’s Algorithm

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

Given an array ‘a[]’ of size n and number of queries q. Each query can be represented by two integers l and r. Your task is to print the number of distinct integers in the subarray l to r. Given a[i] <= 

*** QuickLaTeX cannot compile formula:
10^6    


*** Error message:
Cannot connect to QuickLaTeX server: cURL error 28: Connection timed out after 10000 milliseconds
Please make sure your server/PHP settings allow HTTP requests to external resources ("allow_url_fopen", etc.)
These links might help in finding solution:
http://wordpress.org/extend/plugins/core-control/
http://wordpress.org/support/topic/an-unexpected-http-error-occurred-during-the-api-request-on-wordpress-3?replies=37

Examples :

Input : a[] = {1, 1, 2, 1, 2, 3}
q = 3
0 4
1 3
2 5
Output : 2
2
3
In query 1, number of distinct integers
in a[0...4] is 2 (1, 2)
In query 2, number of distinct integers
in a[1..3] is 2 (1, 2)
In query 3, number of distinct integers
in a[2..5] is 3 (1, 2, 3)

Input : a[] = {7, 3, 5, 9, 7, 6, 4, 3, 2}
q = 4
1 5
0 4
0 7
1 8
Output : 5
4
6
7

Let a[0…n-1] be input array and q[0..m-1] be array of queries. 

Approach :

  1. Sort all queries in a way that queries with L values from 0 to 
    *** QuickLaTeX cannot compile formula:
    \sqrt(n) - 1     
    
    
    *** Error message:
    Cannot connect to QuickLaTeX server: cURL error 28: Connection timed out after 10000 milliseconds
    Please make sure your server/PHP settings allow HTTP requests to external resources ("allow_url_fopen", etc.)
    These links might help in finding solution:
    http://wordpress.org/extend/plugins/core-control/
    http://wordpress.org/support/topic/an-unexpected-http-error-occurred-during-the-api-request-on-wordpress-3?replies=37
    are put together, then all queries from 
    *** QuickLaTeX cannot compile formula:
    \sqrt(n)     
    
    
    *** Error message:
    Cannot connect to QuickLaTeX server: cURL error 28: Connection timed out after 10001 milliseconds
    Please make sure your server/PHP settings allow HTTP requests to external resources ("allow_url_fopen", etc.)
    These links might help in finding solution:
    http://wordpress.org/extend/plugins/core-control/
    http://wordpress.org/support/topic/an-unexpected-http-error-occurred-during-the-api-request-on-wordpress-3?replies=37
    to 
    *** QuickLaTeX cannot compile formula:
    2*\sqrt(n) - 1     
    
    
    *** Error message:
    Cannot connect to QuickLaTeX server: cURL error 28: Connection timed out after 10001 milliseconds
    Please make sure your server/PHP settings allow HTTP requests to external resources ("allow_url_fopen", etc.)
    These links might help in finding solution:
    http://wordpress.org/extend/plugins/core-control/
    http://wordpress.org/support/topic/an-unexpected-http-error-occurred-during-the-api-request-on-wordpress-3?replies=37
    , and so on. All queries within a block are sorted in increasing order of R values.
  2. Initialize an array freq[] of size 
    *** QuickLaTeX cannot compile formula:
    10^6     
    
    
    *** Error message:
    Cannot connect to QuickLaTeX server: cURL error 28: Connection timed out after 10001 milliseconds
    Please make sure your server/PHP settings allow HTTP requests to external resources ("allow_url_fopen", etc.)
    These links might help in finding solution:
    http://wordpress.org/extend/plugins/core-control/
    http://wordpress.org/support/topic/an-unexpected-http-error-occurred-during-the-api-request-on-wordpress-3?replies=37
    with 0 . freq[] array keep count of frequencies of all the elements in lying in a given range.
  3. Process all queries one by one in a way that every query uses number of different elements and frequency array computed in previous query and stores the result in structure.
    • Let ‘curr_Diff_element’ be number of different elements of previous query.
    • Remove extra elements of previous query. For example if previous query is [0, 8] and current query is [3, 9], then remove a[0], a[1] and a[2]
    • Add new elements of current query. In the same example as above, add a[9].
  4. Sort the queries in the same order as they were provided earlier and print their stored results

Adding elements()

  • Increase the frequency of element to be added(freq[a[i]]) by 1.
  • If frequency of element a[i] is 1.Increase curr_diff_element by 1 as 1 new element has been added in range.

Removing elements() 

  • Decrease frequency of element to be removed (a[i]) by 1.
  • if frequency of an element a[i] is 0.Just decrease curr_diff_element by 1 as 1 element has been completely removed from the range.

Note : 

In this algorithm, in step 2, index variable for R change at most O(n * 

*** QuickLaTeX cannot compile formula:
\sqrt(n)     


*** Error message:
Cannot connect to QuickLaTeX server: cURL error 28: Connection timed out after 10001 milliseconds
Please make sure your server/PHP settings allow HTTP requests to external resources ("allow_url_fopen", etc.)
These links might help in finding solution:
http://wordpress.org/extend/plugins/core-control/
http://wordpress.org/support/topic/an-unexpected-http-error-occurred-during-the-api-request-on-wordpress-3?replies=37
) times throughout the run and same for L changes its value at most O(m * 
*** QuickLaTeX cannot compile formula:
\sqrt(n)     


*** Error message:
Cannot connect to QuickLaTeX server: cURL error 28: Connection timed out after 10001 milliseconds
Please make sure your server/PHP settings allow HTTP requests to external resources ("allow_url_fopen", etc.)
These links might help in finding solution:
http://wordpress.org/extend/plugins/core-control/
http://wordpress.org/support/topic/an-unexpected-http-error-occurred-during-the-api-request-on-wordpress-3?replies=37
) times. All these bounds are possible only because sorted queries first in blocks of 
*** QuickLaTeX cannot compile formula:
\sqrt(n)     


*** Error message:
Cannot connect to QuickLaTeX server: cURL error 28: Connection timed out after 10001 milliseconds
Please make sure your server/PHP settings allow HTTP requests to external resources ("allow_url_fopen", etc.)
These links might help in finding solution:
http://wordpress.org/extend/plugins/core-control/
http://wordpress.org/support/topic/an-unexpected-http-error-occurred-during-the-api-request-on-wordpress-3?replies=37
size. The preprocessing part takes O(m Log m) time. Processing all queries takes O(n * 
*** QuickLaTeX cannot compile formula:
\sqrt(n)     


*** Error message:
Cannot connect to QuickLaTeX server: cURL error 28: Connection timed out after 10000 milliseconds
Please make sure your server/PHP settings allow HTTP requests to external resources ("allow_url_fopen", etc.)
These links might help in finding solution:
http://wordpress.org/extend/plugins/core-control/
http://wordpress.org/support/topic/an-unexpected-http-error-occurred-during-the-api-request-on-wordpress-3?replies=37
) + O(m * 
*** QuickLaTeX cannot compile formula:
\sqrt(n)     


*** Error message:
Cannot connect to QuickLaTeX server: cURL error 28: Connection timed out after 10000 milliseconds
Please make sure your server/PHP settings allow HTTP requests to external resources ("allow_url_fopen", etc.)
These links might help in finding solution:
http://wordpress.org/extend/plugins/core-control/
http://wordpress.org/support/topic/an-unexpected-http-error-occurred-during-the-api-request-on-wordpress-3?replies=37
) = O((m+n) *
*** QuickLaTeX cannot compile formula:
\sqrt(n)     


*** Error message:
Cannot connect to QuickLaTeX server: cURL error 28: Connection timed out after 10001 milliseconds
Please make sure your server/PHP settings allow HTTP requests to external resources ("allow_url_fopen", etc.)
These links might help in finding solution:
http://wordpress.org/extend/plugins/core-control/
http://wordpress.org/support/topic/an-unexpected-http-error-occurred-during-the-api-request-on-wordpress-3?replies=37
) time. 

Below is the implementation of above approach : 

CPP

// Program to compute no. of different elements
// of ranges for different range queries
#include <bits/stdc++.h>
using namespace std;
 
// Used in frequency array (maximum value of an
// array element).
const int MAX = 1000000;
 
// Variable to represent block size. This is made
// global so compare() of sort can use it.
int block;
 
// Structure to represent a query range and to store
// index and result of a particular query range
struct Query {
    int L, R, index, result;
};
 
// Function used to sort all queries so that all queries
// of 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;
}
 
// calculate distinct elements of all query ranges.
// m is number of queries n is size of array a[].
void queryResults(int a[], int n, Query q[], int m)
{
    // 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
    // different elements
    int currL = 0, currR = 0;
    int curr_Diff_elements = 0;
 
    // Initialize frequency array with 0
    int freq[MAX] = { 0 };
 
    // Traverse through all queries
    for (int i = 0; i < m; i++) {
         
        // L and R values of current range
        int L = q[i].L, R = q[i].R;
 
        // Remove extra elements of previous range.
        // For example if previous range is [0, 3]
        // and current range is [2, 5], then a[0]
        // and a[1] are subtracted
        while (currL < L) {
             
            // element a[currL] is removed
            freq[a[currL]]--;
            if (freq[a[currL]] == 0)
                curr_Diff_elements--;
             
            currL++;
        }
 
        // Add Elements of current Range
        // Note:- during addition of the left
        // side elements we have to add currL-1
        // because currL is already in range
        while (currL > L) {
            freq[a[currL - 1]]++;
 
            // include a element if it occurs first time
            if (freq[a[currL - 1]] == 1)
                curr_Diff_elements++;
             
            currL--;
        }
        while (currR <= R) {
            freq[a[currR]]++;
 
            // include a element if it occurs first time
            if (freq[a[currR]] == 1)
                curr_Diff_elements++;
             
            currR++;
        }
 
        // Remove elements of previous range. For example
        // when previous range is [0, 10] and current range
        // is [3, 8], then a[9] and a[10] are subtracted
        // Note:- Basically for a previous query L to R
        // currL is L and currR is R+1. So during removal
        // of currR remove currR-1 because currR was
        // never included
        while (currR > R + 1) {
 
            // element a[currL] is removed
            freq[a[currR - 1]]--;
 
            // if occurrence of a number is reduced
            // to zero remove it from list of
            // different elements
            if (freq[a[currR - 1]] == 0)
                curr_Diff_elements--;
             
            currR--;
        }
        q[i].result = curr_Diff_elements;
    }
}
 
// print the result of all range queries in
// initial order of queries
void printResults(Query q[], int m)
{
    sort(q, q + m, compare1);
    for (int i = 0; i < m; i++) {
        cout << "Number of different elements" <<
            " in range " << q[i].L << " to "
            << q[i].R << " are " << q[i].result << endl;
    }
}
 
// Driver program
int main()
{
    int a[] = { 1, 1, 2, 1, 3, 4, 5, 2, 8 };
    int n = sizeof(a) / sizeof(a[0]);
    Query q[] = { { 0, 4, 0, 0 }, { 1, 3, 1, 0 },
                { 2, 4, 2, 0 } };
    int m = sizeof(q) / sizeof(q[0]);
    queryResults(a, n, q, m);
    printResults(q, m);
    return 0;
}

                    

Java

//Java program to compute no. of different elements
// of ranges for different range queries
 
import java.io.*;
import java.util.*;
 
class GFG {
     
    // Class to represent a query range and to store
    // index and result of a particular query range
    public static class Query{
        int L, R, index, result;
        Query(int l, int r, int i, int res){
            this.L = l;
            this.R = r;
            this.index = i;
            this.result = res;
        }
    }
     
    // Used in frequency array (maximum value of an
    // array element).
   public static  int MAX = 1000000;
       
    // Variable to represent block size. This is made
    // global so compare() of sort can use it.
    public static int block;
     
    // calculate distinct elements of all query ranges.
    // m is number of queries n is size of array a[].
    public static void queryResults(int a[], int n, Query q[], int m)
    {
        // Find block size
        block = (int)Math.sqrt(n);
       
        // Sort all queries so that all queries
        // of same block are arranged together and within a block,
        // queries are sorted in increasing order of R values.
        Arrays.sort(q, new Comparator<Query>() {
            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?1:-1;
               
                // Same block, sort by R value
                return x.R < y.R?1:-1;
            }
        });
       
        // Initialize current L, current R and current
        // different elements
        int currL = 0, currR = 0;
        int curr_Diff_elements = 0;
       
        // Initialize frequency array with 0
        int freq[] = new int[MAX];
        Arrays.fill(freq,0);
       
        // Traverse through all queries
        for (int i = 0; i < m; i++) {
               
            // L and R values of current range
            int L = q[i].L, R = q[i].R;
       
            // Remove extra elements of previous range.
            // For example if previous range is [0, 3]
            // and current range is [2, 5], then a[0]
            // and a[1] are subtracted
            while (currL < L) {
                   
                // element a[currL] is removed
                freq[a[currL]]--;
                if (freq[a[currL]] == 0) {
                    curr_Diff_elements--;
                }
                currL++;
            }
       
            // Add Elements of current Range
            // Note:- during addition of the left
            // side elements we have to add currL-1
            // because currL is already in range
            while (currL > L) {
                freq[a[currL - 1]]++;
       
                // include a element if it occurs first time
                if (freq[a[currL - 1]] == 1) {
                    curr_Diff_elements++;
                }
                currL--;
            }
            while (currR <= R) {
                freq[a[currR]]++;
       
                // include a element if it occurs first time
                if (freq[a[currR]] == 1){
                    curr_Diff_elements++;
                }
                currR++;
            }
       
            // Remove elements of previous range. For example
            // when previous range is [0, 10] and current range
            // is [3, 8], then a[9] and a[10] are subtracted
            // Note:- Basically for a previous query L to R
            // currL is L and currR is R+1. So during removal
            // of currR remove currR-1 because currR was
            // never included
            while (currR > R + 1) {
       
                // element a[currL] is removed
                freq[a[currR - 1]]--;
       
                // if occurrence of a number is reduced
                // to zero remove it from list of
                // different elements
                if (freq[a[currR - 1]] == 0){
                    curr_Diff_elements--;
                }
                currR--;
            }
            q[i].result = curr_Diff_elements;
        }
    }
     
    // print the result of all range queries in
    // initial order of queries
    public static void printResults(Query q[], int m)
    {
        // FSort all queries in order of their
        // index value so that results of queries can be printed
        // in same order as of input
        Arrays.sort(q, new Comparator<Query>() {
            public int compare(Query x, Query y) {
                return (x.index < y.index)?-1:1;
            }
        });
         
         
        for (int i = 0; i < m; i++) {
            System.out.println("Number of different elements in range " + q[i].L + " to " + q[i].R + " are " + q[i].result);
        }
    }
     
    //Driver Code
    public static void main (String[] args) {
        int a[] = { 1, 1, 2, 1, 3, 4, 5, 2, 8 };
        int n = a.length;
        Query q[] = new Query[3];
        q[0]=new Query(0,4,0,0);
        q[1] = new Query(1, 3, 1, 0);
        q[2] = new Query( 2, 4, 2, 0);
        int m = q.length;
        queryResults(a, n, q, m);
        printResults(q, m);
    }
}
//This code is contributed by shruti456rawal

                    

Python3

import math
MAX = 1000000
 
# Structure to represent a query range and to store
# index and result of a particular query range
class Query:
    def __init__(self, L, R, index, result):
        self.L = L
        self.R = R
        self.index = index
        self.result = result
 
# 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):
    if x.L // block != y.L // block:
        return x.L // block < y.L // block
    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 the input
def compare1(x, y):
    return x.index < y.index
 
# Calculate distinct elements of all query ranges.
# m is the number of queries, n is the size of array a[].
def queryResults(a, n, q, m):
    global block
    # 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
    # different elements
    currL = 0
    currR = 0
    curr_Diff_elements = 0
 
    # Initialize frequency array with 0
    freq = [0] * (MAX + 1)
 
    # Traverse through all queries
    for i in range(m):
        # L and R values of the current range
        L, R = q[i].L, q[i].R
 
        # Remove extra elements of the previous range.
        # For example, if the previous range is [0, 3]
        # and the current range is [2, 5], then a[0]
        # and a[1] are subtracted
        while currL < L:
            # element a[currL] is removed
            freq[a[currL]] -= 1
            if freq[a[currL]] == 0:
                curr_Diff_elements -= 1
            currL += 1
 
        # Add elements of the current Range
        # Note:- during the addition of the left
        # side elements, we have to add currL-1
        # because currL is already in range
        while currL > L:
            freq[a[currL - 1]] += 1
 
            # include an element if it occurs the first time
            if freq[a[currL - 1]] == 1:
                curr_Diff_elements += 1
            currL -= 1
 
        while currR <= R:
            freq[a[currR]] += 1
 
            # include an element if it occurs the first time
            if freq[a[currR]] == 1:
                curr_Diff_elements += 1
            currR += 1
 
        # Remove elements of the previous range. For example,
        # when the previous range is [0, 10] and the current range
        # is [3, 8], then a[9] and a[10] are subtracted
        # Note:- Basically for a previous query L to R
        # currL is L and currR is R+1. So during the removal
        # of currR remove currR-1 because currR was
        # never included
        while currR > R + 1:
            # element a[currL] is removed
            freq[a[currR - 1]] -= 1
 
            # if the occurrence of a number is reduced
            # to zero remove it from the list of
            # different elements
            if freq[a[currR - 1]] == 0:
                curr_Diff_elements -= 1
            currR -= 1
 
        q[i].result = curr_Diff_elements
 
# print the result of all range queries in
# the initial order of queries
def printResults(q, m):
    q.sort(key=lambda x: x.index)
    for i in range(m):
        print("Number of different elements in range", q[i].L, "to", q[i].R, "are", q[i].result)
 
# Driver program
if __name__ == "__main__":
    a = [1, 1, 2, 1, 3, 4, 5, 2, 8]
    n = len(a)
    q = [Query(0, 4, 0, 0), Query(1, 3, 1, 0), Query(2, 4, 2, 0)]
    m = len(q)
    queryResults(a, n, q, m)
    printResults(q, m)

                    

Output
Number of different elements in range 0 to 4 are 3
Number of different elements in range 1 to 3 are 2
Number of different elements in range 2 to 4 are 3


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