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 :

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

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of above approach
import java.io.*;
import java.util.*;
 
class GFG
{
 
    // Each segment of the segment tree would be a set
    // to maintain distinct elements
    static HashSet<Integer>[] segment;
 
    // Build the segment tree
    // i denotes current node, s denotes start and
    // e denotes the end of range for current node
    static 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].add(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].addAll(segment[2 * i]);
        segment[i].addAll(segment[2 * i + 1]);
    }
 
    // Query in an range a to b
    static HashSet<Integer> query(int node, int l,
                                int r, int a, int b)
    {
        HashSet<Integer> left = new HashSet<>();
        HashSet<Integer> right = new HashSet<>();
        HashSet<Integer> result = new HashSet<>();
 
        // 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.addAll(left);
 
        right = query(1 + 2 * node, 1 + (l + r) / 2, r, a, b);
        result.addAll(right);
 
        // Return the result
        return result;
    }
 
    // Initialize the segment tree
    @SuppressWarnings("unchecked")
    static void init(int n)
    {
 
        // Get the height of the segment tree
        int h = (int) Math.ceil(Math.log(n) / Math.log(2));
        h = (int) (2 * Math.pow(2, h)) - 1;
 
        // Initialize the segment tree
        segment = new HashSet[h];
        for (int i = 0; i < h; i++)
            segment[i] = new HashSet<>();
    }
 
    // Function to get the result for the
    // subarray from arr[l] to arr[r]
    static void getDistinct(int l, int r, int n)
    {
 
        // Query for the range set
        HashSet<Integer> ans = query(1, 0, n - 1, l, r);
 
        System.out.println(ans.size());
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int[] arr = { 1, 1, 2, 1, 3 };
        int n = arr.length;
 
        init(n);
 
        // Bulid the segment tree
        build(1, 0, n - 1, arr);
 
        // Query in range 0 to 4
        getDistinct(0, 4, n);
    }
}
 
// This code is contributed by
// sanjeev2552
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

# python3 implementation of above approach
from math import ceil,log,floor
 
# Each segment of the segment tree would be a set
# to maintain distinct elements
segment=[[] for i in range(1000)]
 
# Build the segment tree
# i denotes current node, s denotes start and
# e denotes the end of range for current node
def build(i, s, e, arr):
 
    # If start is equal to end then
    # append the array element
    if (s == e):
        segment[i].append(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].append(segment[2 * i])
 
    segment[i].append(segment[2 * i + 1])
 
# Query in an range a to b
def query(node, l, r, a, b):
    left, right, result=[],[],[]
 
    # If the range is out of the bounds
    # of this segment
    if (b < l or a > r):
        return result
 
    # If the range lies in this segment
    if (a <= l and r <= b):
        return segment[node]
 
    # Else query for the right and left
    # leaf node of this subtree
    # and append them into the set
    left = query(2 * node, l, (l + r) // 2, a, b)
    result.append(left)
 
    right = query(1 + 2 * node, 1 + (l + r) // 2, r, a, b)
    result.append(right)
 
    # Return the result
    return result
def answer(ans):
    d = {}
    for i in str(ans):
        if i not in ['[',',',']',' ']:
            d[i]=1
    return len(d)
 
# Initialize the segment tree
def init(n):
     
    # Get the height of the segment tree
    h = ceil(log(n, 2))
    h = (2 * (pow(2, h))) - 1
 
# Function to get the result for the
# subarray from arr[l] to arr[r]
def getDistinct(l, r, n):
     
    # Query for the range set
    ans = query(1, 0, n - 1, l, r)
 
    print(answer(str(ans)))
 
# Driver code
arr=[1, 1, 2, 1, 3]
n = len(arr)
 
init(n)
 
# Bulid the segment tree
build(1, 0, n - 1, arr)
 
# Query in range 0 to 4
getDistinct(0, 4, n)
 
# This code is contributed by mohit kumar 29
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# implementation of
// the above approach
using System;
using System.Collections;
using System.Collections.Generic;
class GFG{
  
// Each segment of the segment
// tree would be a set to maintain
// distinct elements
static HashSet<int>[] segment;
  
// Build the segment tree
// i denotes current node,
// s denotes start and
// e denotes the end of
// range for current node
static 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].Add(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
  foreach(int x in segment[2 * i])
  {
    segment[i].Add(x);   
  }
 
  foreach(int x in segment[2 * i + 1])
  {
    segment[i].Add(x);   
  }
}
  
// Query in an range a to b
static HashSet<int> query(int node, int l,
                          int r, int a, int b)
{
  HashSet<int> left = new HashSet<int>();
  HashSet<int> right = new HashSet<int>();
  HashSet<int> result = new HashSet<int>();
 
  // 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);
  foreach(int x in left)
  {
    result.Add(x);   
  }
 
  right = query(1 + 2 * node,
                1 + (l + r) / 2,
                r, a, b);
  foreach(int x in right)
  {
    result.Add(x);   
  }
 
  // Return the result
  return result;
}
 
// Initialize the segment tree
static void init(int n)
{
 
  // Get the height of the segment tree
  int h = (int) Math.Ceiling(Math.Log(n) /
                             Math.Log(2));
  h = (int) (2 * Math.Pow(2, h)) - 1;
 
  // Initialize the segment tree
  segment = new HashSet<int>[h];
   
  for (int i = 0; i < h; i++)
    segment[i] = new HashSet<int>();
}
 
// Function to get the result for the
// subarray from arr[l] to arr[r]
static void getDistinct(int l,
                        int r, int n)
{
  // Query for the range set
  HashSet<int> ans = query(1, 0,
                           n - 1,
                           l, r);
 
  Console.Write(ans.Count);
}
 
// Driver Code
public static void Main(string[] args)
{
  int[] arr = {1, 1, 2, 1, 3};
  int n = arr.Length;
  init(n);
 
  // Bulid the segment tree
  build(1, 0, n - 1, arr);
 
  // Query in range 0 to 4
  getDistinct(0, 4, n);
}
}
 
// This code is contributed by rutvik_56
chevron_right

Output: 
3

 

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

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.





Third 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.



Article Tags :
Practice Tags :