0

Here is The Problem i Want to Solve , I am Using The Fact That Prefix Sum[i] - Prefix Sum[i-1] Leads to Frequency being Greater than Zero to Identify Distinct Digits and Then i am Eliminating The Frequency , But Even with BIT , i am Getting a TLE

Given a sequence of n numbers a1, a2, ..., an and a number of d-queries.

A d-query is a pair (i, j) (1 ≤ i ≤ j ≤ n).

For each d-query (i, j), you have to return the number of distinct elements in the subsequence ai, ai+1, ..., aj.

Input

Line 1: n (1 ≤ n ≤ 30000).
Line 2: n numbers a1, a2, ..., an (1 ≤ ai ≤ 106).
Line 3: q (1 ≤ q ≤ 200000), the number of d-queries.
In the next q lines, each line contains 2 numbers i, j 
representing a d-query (1 ≤ i ≤ j ≤ n).

Output

For each d-query (i, j), print the number of distinct elements in the 
subsequence ai, ai+1, ..., aj in a single line.
Example

Input
5 
1 1 2 1 3
3
1 5
2 4
3 5

Output
3
2
3

the code is:

#include <iostream>
#include <algorithm>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
typedef long long int ll;
using namespace std;
void update(ll n, ll val, vector<ll> &b);
ll read(ll n,vector<ll> &b);
ll readsingle(ll n,vector<ll> &b);
void map(vector<ll> &a,vector<ll> &b,ll n)  /**** RElative Mapping ***/
{
    ll temp;
    a.clear();
    b.clear();
    for(ll i=0; i<n; i++)
    {
        cin>>temp;
        a.push_back(temp);
        b.push_back(temp);
    }
    sort(b.begin(),b.end());
    for(ll i=0; i<n; i++)
        *(a.begin()+i) = (lower_bound(b.begin(),b.end(),a[i])-b.begin())+1;
    b.assign(n+1,0);
}
int main()
{
    ll n;
    cin>>n;
    vector<ll> a,b;
    map(a,b,n);
    ll t;
    cin>>t;
    while(t--)
    {
        ll l ,u;
        b.assign(n+1,0);
        cin>>l>>u;
        l--;/*** Reduce For Zero Based INdex ****/
        u--;
        for(ll i=l;i<=u;i++)
            update(a[i],1,b);
        ll cont=0;
        for(ll i=l;i<=u;i++)
            if(readsingle(a[i],b)>0)
        {
            cont++;
            update(a[i],-readsingle(a[i],b),b); /***Eliminate The Frequency */
        }
        cout<<cont<<endl;
    }
    return 0;
}
ll readsingle(ll n,vector<ll> &b)
{
    return read(n,b)-read(n-1,b);
}
ll read(ll n,vector<ll> &b)
{
    ll sum=0;
    for(; n; sum+=b[n],n-=n&-n);
    return sum;
}
void update(ll n, ll val, vector<ll> &b)
{
    for(; n<=b.size(); b[n]+=val,n+=n&-n);
}

1 Answers1

10

The algorithm you use is too slow. For each query, your iterate over the entire query range, which already gives n * q operations(obviously, it is way too much). Here is a better solution(it has O((n + q) * log n) time and O(n + q) space complexity (it is an offline solution):

  1. Let's sort all queries by their right end(there is no need to sort them explicitly, you can just add a query to an appropriate position (from 0 to n - 1)).

  2. Now let's iterate over all positions in the array from left to right and maintain a BIT. Each position in the BIT is either 1(it means that there is a new element at position i) or 0(initially, it is filled with zeros).

  3. For each element a[i]: if it the first occurrence of this element, just add one to the i position in the BIT. Otherwise, add -1 to the position of the previous occurrence of this element and then add 1 to the i position.

  4. The answer to the query (left, right) is just sum for all elements from left to right.

To maintain the last occurrence of each element, you can use a map.

It is possible to make it online using persistent segment tree(the time complexity would be the same, the same complexity would become O(n * log n + q)), but it is not required here.

kraskevich
  • 18,368
  • 4
  • 33
  • 45
  • As elements in array are only limited from 0 to 10^6, so using an array is enough instead of map, but this solution is nice, thank you :) – Pham Trung Dec 26 '14 at 11:49
  • could you please explain the process for array={3,1,3} and query being (1,1) , 1 based indexed – advocateofnone Dec 26 '14 at 13:19
  • 1
    @migdal We iterate over the array from left to right. The first element is 3. It is the first occurence of this element, so we add 1 to the position 1 in a BIT. Then we answer this query: the sum from 1 to 1 is 1. After that we keep iterating over the array, but it does not matter as there are no more queries. – kraskevich Dec 26 '14 at 13:39
  • understood sorting intervals by end is of great help, nice idea thanks alot – advocateofnone Dec 26 '14 at 13:49
  • @ILoveCoding You said " Otherwise, add -1 to the position of the previous occurrence of this element ". But we need to loop through the previous elements for every element of the array to find if it is the first occurrence. So it would be O(n^2). How do I efficiently find if an element in an element occurred first or has any previous occurrence? – Wasim Thabraze Jan 18 '15 at 03:43
  • 1
    @WasimThabraze We can maintain a map element -> the last occurrence so far when we iterate over the array. In this case, finding the last occurrence is O(1) or O(log N). – kraskevich Jan 18 '15 at 07:48
  • @kraskevich Say arr = {2, 3, 3}. Iteration 1: add 1 to pos 1 in BIT for element arr[0], we have bit = {0, 1, 1, 0}. Iteration 2: add 1 to pos 2 in BIT for element arr[1], bit = {0, 1, 2, 0}. Iteration three: add -1 to pos 2, add 1 to pos 3 for element arr[2]. We have bit = {0, 1, 1, 1}. For query q(2, 3), we perform the query on iteration 3 giving: sum(2, 3) = bit[2] + bit[3] =1 + 1, but arr[1] == arr[2]. So no. of unique elements should be 1. What am I missing? *Note my bit array starts inserting from index 1 – Xaero Jun 17 '17 at 05:56
  • Ah! I get what you mean now. I literally went and summed the bit array when it should be bit[3] - bit[2-1]. Awesome. Thanks! – Xaero Jun 17 '17 at 15:41
  • @xaero I have the same doubt as you. can you please explain it to me. – saurabh gupta Jun 22 '20 at 17:57