Array range queries for elements with frequency same as value

Given an array of N numbers, the task is to answer Q queries of the following type:
query(start, end) = Number of times a number x occurs exactly x times in a subarray from start to end
Examples:Â Â
Input : arr = {1, 2, 2, 3, 3, 3}Â
Query 1: start = 0, end = 1,Â
Query 2: start = 1, end = 1,Â
Query 3: start = 0, end = 2,Â
Query 4: start = 1, end = 3,Â
Query 5: start = 3, end = 5,Â
Query 6: start = 0, end = 5Â
Output : 1 0 2 1 1 3ÂExplanation:
In Query 1, Element 1 occurs once in subarray [1, 2];Â
In Query 2, No Element satisfies the required condition is subarray [2];Â
In Query 3, Element 1 occurs once and 2 occurs twice in subarray [1, 2, 2];Â
In Query 4, Element 2 occurs twice in subarray [2, 2, 3];Â
In Query 5, Element 3 occurs thrice in subarray [3, 3, 3];Â
In Query 6, Element 1 occurs once, 2 occurs twice and 3 occurs thrice in subarray [1, 2, 2, 3, 3, 3]Â
Method 1 (Brute Force): Calculate frequency of every element in the subarray under each query. If any number x has frequency x in the subarray covered under each query, we increment the counter. Â
Implementation:
C++
/* C++ Program to answer Q queries to    find number of times an element x    appears x times in a Query subarray */#include <bits/stdc++.h>using namespace std;Â
/* Returns the count of number x with   frequency x in the subarray from    start to end */int solveQuery(int start, int end, int arr[]){    // map for frequency of elements    unordered_map<int, int> frequency;Â
    // store frequency of each element     // in arr[start; end]    for (int i = start; i <= end; i++)         frequency[arr[i]]++;   Â
    // Count elements with same frequency    // as value    int count = 0;    for (auto x : frequency)         if (x.first == x.second)             count++;       return count;}Â
int main(){Â Â Â Â int A[] = { 1, 2, 2, 3, 3, 3 };Â Â Â Â int n = sizeof(A) / sizeof(A[0]);Â
    // 2D array of queries with 2 columns    int queries[][3] = { { 0, 1 },                         { 1, 1 },                         { 0, 2 },                         { 1, 3 },                         { 3, 5 },                         { 0, 5 } };Â
    // calculating number of queries    int q = sizeof(queries) / sizeof(queries[0]);Â
    for (int i = 0; i < q; i++) {        int start = queries[i][0];        int end = queries[i][1];        cout << "Answer for Query " << (i + 1)             << " = " << solveQuery(start,             end, A) << endl;    }Â
    return 0;} |
Java
/* Java Program to answer Q queries to find number of times an element x appears x times in a Query subarray */import java.util.HashMap;import java.util.Map;Â
class GFG {Â
Â
/* Returns the count of number x withfrequency x in the subarray from start to end */static int solveQuery(int start, int end, int arr[]){    // map for frequency of elements    Map<Integer,Integer> mp = new HashMap<>();Â
    // store frequency of each element     // in arr[start; end]    for (int i = start; i <= end; i++)         mp.put(arr[i],mp.get(arr[i]) == null?1:mp.get(arr[i])+1); Â
    // Count elements with same frequency    // as value    int count = 0;    for (Map.Entry<Integer,Integer> entry : mp.entrySet())         if (entry.getKey() == entry.getValue())             count++;     return count;}Â
// Driver codepublic static void main(String[] args) {Â Â Â Â int A[] = { 1, 2, 2, 3, 3, 3 };Â Â Â Â int n = A.length;Â
    // 2D array of queries with 2 columns    int [][]queries = { { 0, 1 },                        { 1, 1 },                        { 0, 2 },                        { 1, 3 },                        { 3, 5 },                        { 0, 5 } };Â
    // calculating number of queries    int q = queries.length;Â
    for (int i = 0; i < q; i++)     {        int start = queries[i][0];        int end = queries[i][1];        System.out.println("Answer for Query " + (i + 1)            + " = " + solveQuery(start,            end, A));    }}}Â
// This code is contributed by Rajput-Ji |
Python3
# Python 3 Program to answer Q queries # to find number of times an element x # appears x times in a Query subarrayimport math as mtÂ
# Returns the count of number x with# frequency x in the subarray from # start to enddef solveQuery(start, end, arr):Â
    # map for frequency of elements    frequency = dict()Â
    # store frequency of each element     # in arr[start end]    for i in range(start, end + 1):Â
Â
        if arr[i] in frequency.keys():            frequency[arr[i]] += 1        else:            frequency[arr[i]] = 1                     # Count elements with same     # frequency as value    count = 0    for x in frequency:         if x == frequency[x]:             count += 1    return countÂ
# Driver code A = [1, 2, 2, 3, 3, 3 ]n = len(A)Â
# 2D array of queries with 2 columnsqueries = [[ 0, 1 ], [ 1, 1 ],           [ 0, 2 ], [ 1, 3 ],           [ 3, 5 ], [ 0, 5 ]]Â
# calculating number of queriesq = len(queries)Â
for i in range(q):Â Â Â Â start = queries[i][0]Â Â Â Â end = queries[i][1]Â Â Â Â print("Answer for Query ", (i + 1), Â Â Â Â Â Â Â Â Â Â " = ", solveQuery(start,end, A))Â Â Â Â Â Â Â Â Â Â Â # This code is contributed # by Mohit kumar 29 |
C#
// C# Program to answer Q queries to // find number of times an element x // appears x times in a Query subarrayusing System;using System.Collections.Generic;Â
class GFG{    /* Returns the count of number x with     frequency x in the subarray from     start to end */    public static int solveQuery(int start,                                  int end,                                  int[] arr)    {Â
        // map for frequency of elements         Dictionary<int,                    int> mp = new Dictionary<int,                                             int>();Â
        // store frequency of each element         // in arr[start; end]         for (int i = start; i <= end; i++)        {            if (mp.ContainsKey(arr[i]))                mp[arr[i]]++;            else                mp.Add(arr[i], 1);        }Â
        // Count elements with same frequency         // as value         int count = 0;        foreach (KeyValuePair<int,                               int> entry in mp)        {            if (entry.Key == entry.Value)                count++;        }        return count;    }Â
    // Driver code     public static void Main(String[] args)    {        int[] A = { 1, 2, 2, 3, 3, 3 };        int n = A.Length;Â
        // 2D array of queries with 2 columns         int[,] queries = {{ 0, 1 }, { 1, 1 },                          { 0, 2 }, { 1, 3 },                          { 3, 5 }, { 0, 5 }};Â
        // calculating number of queries         int q = queries.Length;Â
        for (int i = 0; i < q; i++)        {            int start = queries[i, 0];            int end = queries[i, 1];            Console.WriteLine("Answer for Query " + (i + 1) +                              " = " + solveQuery(start, end, A));        }    }}Â
// This code is contributed by// sanjeev2552 |
Javascript
<script>/* Javascript Program to answer Q queries to find number of times an element x appears x times in a Query subarray */         /* Returns the count of number x withfrequency x in the subarray from start to end */    function solveQuery(start,end,arr)    {        // map for frequency of elements    let mp = new Map();       // store frequency of each element     // in arr[start; end]    for (let i = start; i <= end; i++)         mp.set(arr[i],mp.get(arr[i]) == null?1:mp.get(arr[i])+1);        // Count elements with same frequency    // as value    let count = 0;    for (let [key, value] of mp.entries())         if (key == value)             count++;     return count;    }         // Driver code    let A=[1, 2, 2, 3, 3, 3];    let n = A.length;    // 2D array of queries with 2 columns    let queries = [[ 0, 1 ], [ 1, 1 ],           [ 0, 2 ], [ 1, 3 ],           [ 3, 5 ], [ 0, 5 ]];         // calculating number of queries    let q = queries.length;    for (let i = 0; i < q; i++)     {        let start = queries[i][0];        let end = queries[i][1];        document.write("Answer for Query " + (i + 1)            + " = " + solveQuery(start,            end, A)+"<br>");    }Â
// This code is contributed by unknown2108</script> |
Answer for Query 1 = 1 Answer for Query 2 = 0 Answer for Query 3 = 2 Answer for Query 4 = 1 Answer for Query 5 = 1 Answer for Query 6 = 3
Time Complexity: O(Q * N)
Auxiliary Space: O(N)
Method 2 (Efficient):
We can solve this problem using the MO’s Algorithm.Â
We assign starting index, ending index and query number to each query, Each query takes the following form-
Starting Index(L): Starting Index of the subarray covered under the query;Â
Ending Index(R) : Ending Index of the subarray covered under the query;Â
Query Number(Index) : Since queries are sorted, this tells us original position of the query so that we answer the queries in the original order
Firstly, we divide the queries into blocks and sort the queries using a custom comparator.Â
Now we process the queries offline where we keep two pointers i.e. MO_RIGHT and MO_LEFT with each incoming query, we move these pointers forward and backward and insert and delete elements according to the starting and ending indices of the current query.Â
Let the current running answer be current_ans.
Whenever we insert an element we increment the frequency of the included element, if this frequency is equal to the element we just included, we increment the current_ans.If the frequency of this element becomes (current element + 1) this means that earlier this element was counted in the current_ans when it was equal to its frequency, thus we need to decrement current_ans in this case.Â
Whenever we delete/remove an element we decrement the frequency of the excluded element, if this frequency is equal to the element we just excluded, we increment the current_ans.If the frequency of this element becomes (current element – 1) this means that earlier this element was counted in the current_ans when it was equal to its frequency, thus we need to decrement current_ans in this case.
Implementation:
C++
/* C++ Program to answer Q queries to   find number of times an element x    appears x times in a Query subarray */#include <bits/stdc++.h>using namespace std;Â
// Variable to represent block size. // This is made global so compare() // of sort can use it.int block;Â
// Structure to represent a query rangestruct Query {Â Â Â Â int L, R, index;};Â
/* 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;}Â
/* Inserts element (x) into current range   and updates current answer */void add(int x, int& currentAns,          unordered_map<int, int>& freq){Â
    // increment frequency of this element    freq[x]++;Â
    // if this element was previously     // contributing to the currentAns,    // decrement currentAns    if (freq[x] == (x + 1))        currentAns--;Â
    // if this element has frequency     // equal to its value, increment    // currentAns    else if (freq[x] == x)        currentAns++;}Â
/* Removes element (x) from current    range btw L and R and updates    current Answer */void remove(int x, int& currentAns,             unordered_map<int, int>& freq){Â
    // decrement frequency of this element    freq[x]--;Â
    // if this element has frequency equal     // to its value, increment currentAns    if (freq[x] == x)        currentAns++;Â
    // if this element was previously     // contributing to the currentAns     // decrement currentAns    else if (freq[x] == (x - 1))         currentAns--;}Â
/* Utility Function to answer all queries   and build the ans array in the original    order of queries */void queryResultsUtil(int a[], Query q[],                         int ans[], int m){Â
    // map to store freq of each element    unordered_map<int, int> freq;Â
    // Initialize current L, current R    // and current sum    int currL = 0, currR = 0;    int currentAns = 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;         int index = q[i].index;Â
        // 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         // removed        while (currL < L) {            remove(a[currL], currentAns, freq);            currL++;        }Â
        // Add Elements of current Range        while (currL > L) {            currL--;            add(a[currL], currentAns, freq);        }        while (currR <= R) {            add(a[currR], currentAns, freq);            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 Removed        while (currR > R + 1) {            currR--;            remove(a[currR], currentAns, freq);        }Â
        // Store current ans as the Query ans for        // Query number index        ans[index] = currentAns;    }}Â
/* Wrapper for queryResultsUtil() and outputs the   ans array constructed by answering all queries */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);Â
    int* ans = new int[m];    queryResultsUtil(a, q, ans, m);Â
    for (int i = 0; i < m; i++) {        cout << "Answer for Query " << (i + 1)             << " = " << ans[i] << endl;    }}Â
// Driver programint main(){Â Â Â Â int A[] = { 1, 2, 2, 3, 3, 3 };Â
    int n = sizeof(A) / sizeof(A[0]);Â
    // 2D array of queries with 2 columns    Query queries[] = { { 0, 1, 0 },                        { 1, 1, 1 },                        { 0, 2, 2 },                        { 1, 3, 3 },                        { 3, 5, 4 },                        { 0, 5, 5 } };Â
    // calculating number of queries    int q = sizeof(queries) / sizeof(queries[0]);Â
    // Print result for each Query    queryResults(A, n, queries, q);Â
    return 0;} |
Java
/* Java Program to answer Q queries to   find number of times an element x    appears x times in a Query subarray */Â
import java.util.*;Â
public class GFG {Â
Â
    // 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 {        int L, R, index;Â
        Query(int L, int R, int index) {            this.L = L;            this.R = R;            this.index = index;        }    }         /* 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. */    static boolean 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;    }         /* Inserts element (x) into current range       and updates current answer */    static void add(int x, int[] currentAns, HashMap<Integer, Integer> freq) {                  // increment frequency of this element        freq.put(x, freq.getOrDefault(x, 0) + 1);                  // if this element was previously         // contributing to the currentAns,        // decrement currentAns        if (freq.get(x) == (x + 1)) {            currentAns[0]--;                              // if this element has frequency         // equal to its value, increment        // currentAns        } else if (freq.get(x) == x) {            currentAns[0]++;        }    }         /* Removes element (x) from current     range btw L and R and updates     current Answer */Â
    static void remove(int x, int[] currentAns, HashMap<Integer, Integer> freq) {                 // decrement frequency of this element        freq.put(x, freq.get(x) - 1);                     // if this element has frequency equal                // to its value, increment currentAns        if (freq.get(x) == x) {            currentAns[0]++;                         // if this element was previously             // contributing to the currentAns             // decrement currentAns        } else if (freq.get(x) == (x - 1)) {            currentAns[0]--;        }    }         /* Utility Function to answer all queries    and build the ans array in the original     order of queries */    static void queryResultsUtil(int[] a, Query[] q, int[] ans, int m) {                          // map to store freq of each element        HashMap<Integer, Integer> freq = new HashMap<>();                     // Initialize current L, current R        // and current sum        int currL = 0, currR = 0;        int[] currentAns = {0};Â
        // Traverse through all queries        for (int i = 0; i < m; i++) {Â
            int L = q[i].L, R = q[i].R;            int index = q[i].index;                         // 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             // removed            while (currL < L) {                remove(a[currL], currentAns, freq);                currL++;            }                         // Add Elements of current Range            while (currL > L) {                currL--;                add(a[currL], currentAns, freq);            }Â
            while (currR <= R) {                add(a[currR], currentAns, freq);                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 Removed            while (currR > R + 1) {                currR--;                remove(a[currR], currentAns, freq);            }                         // Store current ans as the Query ans for            // Query number index            ans[index] = currentAns[0];        }    }              /* Wrapper for queryResultsUtil() and outputs the   ans array constructed by answering all queries */Â
    static void queryResults(int[] a, int n, Query[] q, int m) {        // Find block size        block = (int) Math.sqrt(n);Â
        Arrays.sort(q, new Comparator<Query>() {    @Override    public int compare(Query x, Query y) {        // Different blocks, sort by block.        if (x.L / block != y.L / block)            return Integer.compare(x.L / block, y.L / block);Â
        // Same block, sort by R value        return Integer.compare(x.R, y.R);    }});Â
        int[] ans = new int[m];        queryResultsUtil(a, q, ans, m);Â
        for (int i = 0; i < m; i++) {            System.out.println("Answer for Query " + (i + 1) + " = " + ans[i]);        }    }Â
    public static void main(String[] args) {        int[] A = {1, 2, 2, 3, 3, 3};        int n = A.length;Â
        // 2D array of queries with 2 columns        Query[] queries = {            new Query(0, 1, 0),            new Query(1, 1, 1),            new Query(0, 2, 2),            new Query(1, 3, 3),            new Query(3, 5, 4),            new Query(0, 5, 5)        };Â
        // calculating number of queries        int q = queries.length;Â
        // Print result for each Query        queryResults(A, n, queries, q);    }}Â
//this code is contributed by bhardwajji |
Python3
# /* python Program to answer Q queries to#Â Â Â find number of times an element x #Â Â Â appears x times in a Query subarray */from functools import cmp_to_keyimport mathÂ
# Variable to represent block size. # This is made global so compare() # of sort can use it.block = 0Â
# Structure to represent a query rangeclass Query:Â
    def __init__(self, L, R, index):        self.L = L        self.R = R        self.index = index     Â
Â
# /* 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. */def Compare(x, y):            # Different blocks, sort by block.    if (block != 0 and x.L / block != y.L / block):        return x.L / block - y.L / blockÂ
    # Same block, sort by R value    return x.R- y.RÂ
# /* Inserts element (x) into current range#Â Â Â and updates current answer */def add(x, currentAns, freq):Â
     # increment frequency of this element    if(x in freq):        freq[x] = freq[x] + 1    else:        freq[x] = 1Â
    # if this element was previously     # contributing to the currentAns,    # decrement currentAns    if (freq[x] == (x + 1)):        currentAns[0] = currentAns[0] - 1Â
Â
     # if this element has frequency      # equal to its value, increment     # currentAns    elif(freq[x] == x):        currentAns[0] = currentAns[0] + 1         Â
# /* Removes element (x) from current # range btw L and R and updates # current Answer */Â
def remove(x, currentAns, freq):Â
    # decrement frequency of this element    freq[x] = freq[x] - 1;Â
    # if this element has frequency equal     # to its value, increment currentAns    if (freq[x] == x):        currentAns[0] = currentAns[0] + 1Â
        # if this element was previously         # contributing to the currentAns         # decrement currentAns    elif(freq[x] == (x-1)):        currentAns[0] = currentAns[0] - 1Â
# /* Utility Function to answer all queries# and build the ans array in the original # order of queries */def queryResultsUtil(a, q, ans, m):Â
Â
    # map to store freq of each element    freq = {}Â
    # Initialize current L, current R    # and current sum    currL = 0    currR = 0    currentAns = [0]Â
    # Traverse through all queries    for i in range(m):Â
        L = q[i].L        R = q[i].R        index = q[i].indexÂ
        # 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         # removed        while (currL < L):            remove(a[currL], currentAns, freq)            currL = currL + 1Â
        # Add Elements of current Range        while (currL > L):            currL = currL - 1            add(a[currL], currentAns, freq)Â
        while (currR <= R):            add(a[currR], currentAns, freq)            currR = currR + 1Â
        # 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 Removed        while (currR > R + 1):            currR = currR - 1            remove(a[currR], currentAns, freq)Â
        # Store current ans as the Query ans for        # Query number index        ans[index] = currentAns[0]         Â
Â
# /* Wrapper for queryResultsUtil() and outputs the# ans array constructed by answering all queries */Â
def queryResults(a, n, q, m):    # Find block size    block = math.floor(math.sqrt(n))Â
        sorted(q, key=cmp_to_key(Compare))Â
    ans = [0]*m    queryResultsUtil(a, q, ans, m)Â
    for i in range(m):        print("Answer for Query " ,(i + 1) ," = " ,ans[i])Â
Â
A = [1, 2, 2, 3, 3, 3]n = len(A)Â
# 2D array of queries with 2 columnsqueries = [    Query(0, 1, 0),    Query(1, 1, 1),    Query(0, 2, 2),    Query(1, 3, 3),    Query(3, 5, 4),    Query(0, 5, 5)]Â
# calculating number of queriesq = len(queries)Â
# Print result for each QueryqueryResults(A, n, queries, q)Â
# this code is contributed by Arushi Jindal. |
Javascript
/* Javascript Program to answer Q queries to   find number of times an element x    appears x times in a Query subarray */Â
Â
Â
// Variable to represent block size. // This is made global so compare() // of sort can use it.let block = 0;Â
// Structure to represent a query rangeclass Query {Â
    constructor(L, R, index) {        this.L = L;        this.R = R;        this.index = index;    }}Â
/* Function used to sort all queries so that all queries of same blockare 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 (x.L / block != y.L / block)        return x.L / block - y.L / block;Â
    // Same block, sort by R value    return x.R- y.R;Â
}Â
/* Inserts element (x) into current range   and updates current answer */function add(x, currentAns, freq) {Â
     // increment frequency of this element    if(x in freq){        freq[x] = freq[x] + 1;    }    else{        freq[x] = 1;    }Â
     // if this element was previously     // contributing to the currentAns,    // decrement currentAns    if (freq[x] == (x + 1)) {        currentAns[0]--;Â
Â
    // if this element has frequency     // equal to its value, increment    // currentAns    } else if (freq[x] == x) {        currentAns[0]++;    }}Â
/* Removes element (x) from current range btw L and R and updates current Answer */Â
function remove(x, currentAns, freq) {Â
    // decrement frequency of this element    freq[x] = freq[x] - 1;Â
        // if this element has frequency equal            // to its value, increment currentAns    if (freq[x] == x) {        currentAns[0]++;Â
        // if this element was previously         // contributing to the currentAns         // decrement currentAns    } else if (freq[x] == (x - 1)) {        currentAns[0]--;    }}Â
/* Utility Function to answer all queriesand build the ans array in the original order of queries */function queryResultsUtil(a, q, ans, m) {Â
Â
    // map to store freq of each element    let freq = {}Â
    // Initialize current L, current R    // and current sum    let currL = 0, currR = 0;    let currentAns = [0];Â
    // Traverse through all queries    for (let i = 0; i < m; i++) {Â
        let L = q[i].L, R = q[i].R;        let index = q[i].index;Â
        // 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         // removed        while (currL < L) {            remove(a[currL], currentAns, freq);            currL++;        }Â
        // Add Elements of current Range        while (currL > L) {            currL--;            add(a[currL], currentAns, freq);        }Â
        while (currR <= R) {            add(a[currR], currentAns, freq);            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 Removed        while (currR > R + 1) {            currR--;            remove(a[currR], currentAns, freq);        }Â
        // Store current ans as the Query ans for        // Query number index        ans[index] = currentAns[0];    }}Â
Â
/* Wrapper for queryResultsUtil() and outputs theans array constructed by answering all queries */Â
function queryResults(a, n, q, m) {    // Find block size    block = Math.floor(Math.sqrt(n));Â
    q.sort(Compare);Â
    let ans = new Array(m);    queryResultsUtil(a, q, ans, m);Â
    for (let i = 0; i < m; i++) {        console.log("Answer for Query " + (i + 1) + " = " + ans[i]);    }}Â
Â
let A = [1, 2, 2, 3, 3, 3];let n = A.length;Â
// 2D array of queries with 2 columnslet queries = [    new Query(0, 1, 0),    new Query(1, 1, 1),    new Query(0, 2, 2),    new Query(1, 3, 3),    new Query(3, 5, 4),    new Query(0, 5, 5)];Â
// calculating number of querieslet q = queries.length;Â
// Print result for each QueryqueryResults(A, n, queries, q);Â
//this code is contributed by Arushi Jindal. |
C#
/* C# Program to answer Q queries to   find number of times an element x    appears x times in a Query subarray */Â
using System;using System.Collections.Generic;Â
public class GFG {// Variable to represent block size. // This is made global so compare() // of sort can use it.    static int block;Â
Â
/* Inserts element (x) into current range   and updates current answer *//* Removes element (x) from current    range btw L and R and updates    current Answer */    static void add(int x, int[] currentAns,                    Dictionary<int, int> freq)    {        freq.TryGetValue(x, out int value);        freq[x] = value + 1;        if (freq[x] == x + 1) {            currentAns[0]--;        }        else if (freq[x] == x) {            currentAns[0]++;        }    }/* Removes element (x) from current    range btw L and R and updates    current Answer */    static void remove(int x, int[] currentAns,                       Dictionary<int, int> freq)    {        freq[x]--;        if (freq[x] == x) {            currentAns[0]++;        }        else if (freq[x] == x - 1) {            currentAns[0]--;        }    }// Structure to represent a query range    class Query {        public int L;        public int R;        public int index;Â
        public Query(int L, int R, int index)        {            this.L = L;            this.R = R;            this.index = index;        }    }    /* Utility Function to answer all queries   and build the ans array in the original    order of queries */static void queryResultsUtil(int[] a, Query[] q,                                 int[] ans, int m)    {         // map to store freq of each element        var freq = new Dictionary<int, int>();        // Initialize current L, current R    // and current sum        int currL = 0, currR = 0;        int[] currentAns = { 0 }; // Traverse through all queries        for (int i = 0; i < m; i++) {            int L = q[i].L, R = q[i].R;            int index = q[i].index; // 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         // removed            while (currL < L) {                remove(a[currL], currentAns, freq);                currL++;            }     // Add Elements of current Range            while (currL > L) {                currL--;                add(a[currL], currentAns, freq);            }Â
            while (currR <= R) {                add(a[currR], currentAns, freq);                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 Removed            while (currR > R + 1) {                currR--;                remove(a[currR], currentAns, freq);            }Â
            ans[index] = currentAns[0];        }    }         /* Wrapper for queryResultsUtil() and outputs the   ans array constructed by answering all queries */Â
    static void queryResults(int[] a, int n, Query[] q,                             int m)    {        block = (int)Math.Sqrt(n);Â
        Array.Sort(q, (x, y) => {            /* 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. */            if (x.L / block != y.L / block) {                return x.L / block - y.L / block;            }            return x.R - y.R;        });Â
        int[] ans = new int[m];        queryResultsUtil(a, q, ans, m);Â
        for (int i = 0; i < m; i++) {            Console.WriteLine("Answer for Query " + (i + 1)                              + " = " + ans[i]);        }    }Â
         public static void Main(string[] args)    {        int[] A = { 1, 2, 2, 3, 3, 3 };        int n = A.Length;Â
        Query[] q            = { new Query(0, 1, 0), new Query(1, 1, 1),                new Query(0, 2, 2), new Query(1, 3, 3),                new Query(3, 5, 4), new Query(0, 5, 5) };        int m = q.Length;Â
        queryResults(A, n, q, m);    }} |
Answer for Query 1 = 1 Answer for Query 2 = 0 Answer for Query 3 = 2 Answer for Query 4 = 1 Answer for Query 5 = 1 Answer for Query 6 = 3
Time Complexity of this approach using MO’s Algorithm is O(Q * sqrt(N) * logA) where logA is the complexity to insert an element A into the unordered_map for each query.
Auxiliary Space: O(N+Q)
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 zambiatek!



