0

これが私が解決したい問題です。私はThe Fact That Prefix Sum[i] - Prefix Sum[i-1]リードを使用してゼロよりも大きい周波数を使用して個別の数字を識別し、次に周波数を排除していますが、BITを使用してもTLEを取得しています

n 個の数値 a1、a2、...、an および多数の d クエリのシーケンスが与えられます。

d-query はペア (i, j) (1 ≤ i ≤ j ≤ n) です。

各 d クエリ (i、j) について、サブシーケンス 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

コードは次のとおりです。

#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);
}
4

1 に答える 1

10

使用しているアルゴリズムが遅すぎます。クエリごとに、クエリ範囲全体を反復処理します。これにより、すでにn * q操作が行われます(明らかに、多すぎます)。これはより良い解決策です(O((n + q) * log n)時間とO(n + q)空間の複雑さがあります(オフラインの解決策です)):

  1. すべてのクエリを右端で並べ替えましょう (明示的に並べ替える必要はありません。適切な位置 (から0までn - 1) にクエリを追加するだけです)。

  2. 次に、配列内のすべての位置を左から右に反復し、BIT を維持します。BIT 内の各位置は1(位置 に新しい要素があることを意味しますi) または0(最初はゼロで埋められます) のいずれかです。

  3. 各要素についてa[i]: この要素が最初に出現する場合iは、BIT 内の位置に 1 を追加します。それ以外の場合は、-1この要素が前に出現した位置に追加して1から、その位置に追加しiます。

  4. クエリの答えは、からまで(left, right)のすべての要素の合計です。leftright

各要素の最後の発生を維持するために、マップを使用できます。

永続的なセグメント ツリーを使用してオンラインにすることは可能ですが (時間の複雑さは同じで、同じ複雑さは になりますO(n * log n + q))、ここでは必須ではありません。

于 2014-12-26T11:36:24.247 に答える