UVa 11235 - Frequent values

Summary
Given a sequence of non-decreasing integers and several queries. Each query is a range [x,y] and you must find the number of occurrences of the most frequent value within the given range.

Explanation
Segment tree data structure can be used to query the range and find out the most frequent value in that range. However, a pre-calculation on the original non-decreasing sequence of integers is needed. The non-decreasing part gives a big hint: it means that integers that have the same value in the sequence, will be clustered together. So, to count the frequency of a certain integer value, we only need to look at adjacent (or consecutive) integers in the sequence.

Consider a sequence of 10 integers:

-1 -1 1 1 1 1 3 10 10 10

Create a frequency sequence that counts the frequency of the original sequence:

2 2 4 4 4 4 1 3 3 3

Then, if you build a segment tree (Range Maximum Query) on this frequency sequence, then you can use it to answer queries.

For example, a query [1, 10] can be answered quite easily using Range Maximum Query in O(log(N)), the answer is 4.

However, a care must be taken for queries that are partial like: [5,10]. In this case, applying the Range Maximum Query directly will give you 4 (which is wrong). For partial query like this, you must adjust the query range to its complete frequency boundary. So, you divide the query [5,10] to two sub-queries: [5,6] and [7,10]. The sub-query [5,6] can be answered easily using math (all the values in this range are equal, so the frequency is 6-5+1 == 2), and the sub-query [7,10] now can be answered correctly using the Range Maximum Query since the range [7,10] is not partial. Finally, you return the maximum frequency of those two sub-queries.

To adjust the range, a simple iteration will do. This can be further speed up by indexing the boundaries using another array and then answered in O(1).

Gotchas

 * The partial query can be at the beginning of the range as well as the end of the range. In this case, you must adjust the beginning as well as the end range of the query.

Input
10 3 -1 -1 1 1 1 1 3 10 10 10 2 3 1 10 5 10 0

Output
1 4 3