Queries for number of distinct elements in a subarray | Set 2

Given an array arr[] of N integers and Q queries. Each query can be represented by two integers L and R. The task is to find the count of distinct integers in the subarray arr[L] to arr[R].

Examples:

Input: arr[] = {1, 1, 3, 3, 5, 5, 7, 7, 9, 9 }, L = 0, R = 4
Output: 3



Input: arr[] = { 1, 1, 2, 1, 3 }, L = 1, R = 3
Output : 2

Naive approach: In this approach, we will traverse through the range l, r and use a set to find all the distinct elements in the range and print them.
Time Complexity: O(q*n)

Efficient approach: Idea is to form a segment tree in which the nodes will store all the distinct elements in the range. For this purpose we can use a self-balancing BST or “set” data structure in C++.
Each query will return the size of the set.

Below is the implementation of the above approach:

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of above approach
#include <bits/stdc++.h>
using namespace std;
  
// Each segment of the segment tree would be a set
// to maintain distinct elements
set<int>* segment;
  
// Build the segment tree
// i denotes current node, s denotes start and
// e denotes the end of range for current node
void build(int i, int s, int e, int arr[])
{
  
    // If start is equal to end then
    // insert the array element
    if (s == e) {
        segment[i].insert(arr[s]);
        return;
    }
  
    // Else divide the range into two halves
    // (start to mid) and (mid+1 to end)
    // first half will be the left node
    // and the second half will be the right node
    build(2 * i, s, (s + e) / 2, arr);
    build(1 + 2 * i, 1 + (s + e) / 2, e, arr);
  
    // Insert the sets of right and left
    // node of the segment tree
    segment[i].insert(segment[2 * i].begin(),
                      segment[2 * i].end());
  
    segment[i].insert(segment[2 * i + 1].begin(),
                      segment[2 * i + 1].end());
}
  
// Query in an range a to b
set<int> query(int node, int l, int r, int a, int b)
{
    set<int> left, right, result;
  
    // If the range is out of the bounds
    // of this segment
    if (b < l || a > r)
        return result;
  
    // If the range lies in this segment
    if (a <= l && r <= b)
        return segment[node];
  
    // Else query for the right and left
    // leaf node of this subtree
    // and insert them into the set
    left = query(2 * node, l, (l + r) / 2, a, b);
    result.insert(left.begin(), left.end());
  
    right = query(1 + 2 * node, 1 + (l + r) / 2, r, a, b);
    result.insert(right.begin(), right.end());
  
    // Return the result
    return result;
}
  
// Initialize the segment tree
void init(int n)
{
    // Get the height of the segment tree
    int h = (int)ceil(log2(n));
    h = (2 * (pow(2, h))) - 1;
  
    // Initialize the segment tree
    segment = new set<int>[h];
}
  
// Function to get the result for the
// subarray from arr[l] to arr[r]
void getDistinct(int l, int r, int n)
{
    // Query for the range set
    set<int> ans = query(1, 0, n - 1, l, r);
  
    cout << ans.size() << endl;
}
  
// Driver code
int main()
{
  
    int arr[] = { 1, 1, 2, 1, 3 };
    int n = sizeof(arr) / sizeof(arr[0]);
  
    init(n);
  
    // Bulid the segment tree
    build(1, 0, n - 1, arr);
  
    // Query in range 0 to 4
    getDistinct(0, 4, n);
  
    return 0;
}

chevron_right


Output:

3

Time Complexity: O(q*log(n))



My Personal Notes arrow_drop_up

Second year Department of Information Technology Jadavpur University

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.