You can answer any of your queries in constant time by performing a preliminary calculation of the quadratic time :
For every i from 0 to n-1 S <- new empty set backed by hashtable; C <- 0; For every j from i to n-1 If A[j] does not belong to S, increment C and add A[j] to S. Stock C as the answer for the query associated to interval i..j.
This algorithm takes quadratic time, since for each interval we perform a limited number of operations, each of which takes constant time (note that the set S is based on a hash table), and there is a quadratic number of intervals.
If you do not have additional information about the queries (total number of queries, distribution of intervals), you cannot do much better, since the total number of intervals is already quadratic.
You can exchange quadratic pre-compression for n linear calculations on the fly: after receiving a request of the form A [i..j] to the pre-path (in O(n) time) the answer is for all intervals A[i..k] , k>=i . This ensures that the amortized complexity remains quadratic and you will not be forced to perform a full quadratic preliminary calculation at the beginning.
Note that the obvious algorithm (the one that you call the obvious in the statement) is cubic, since you are completely scanning every interval.
source share