SPOJ DQUERY : TLE Even With BIT?

2019-02-21 02:59发布

问题:

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:

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.