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)