【SPOJ 】 DQUERY 【莫队 - 区间几个不同数字】

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

分析: 理解了莫队算法,这个就很轻松了
这里的数据范围很小,如果很大可能要用到离散化处理一下。
时间复杂度o((M+N) *sqr(N))

#include<bits/stdc++.h>
using namespace std;
#define LL long long

const int N = 3e4+11;
const int M = 200000+11;
const int MAX = 1e6+11;

const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
const int inff = 0x3f3f3f3f3f3f3f3f;

int B;
struct Query{
    int le,ri;
    int id;
    bool operator < (const Query &b) const {
        if( le/ B == b.le / B) return ri < b.ri;
        else return le/ B < b.le / B;
    }
}Q[M]; int ANS[M];

int cnt[MAX]; int a[N]; int ans;
void Add(int x){
    x=a[x];
    if(cnt[x]==0) ans++;
    cnt[x]++;
}
void Del(int x){
    x=a[x];
    cnt[x]--;
    if(cnt[x]==0) ans--;
}

void solve(int q){
    sort(Q+1,Q+q+1);
    memset(cnt,0,sizeof(cnt));
    int L=1,R=0;  ans=0;
    for(int i=1;i<=q;i++){
        while(R<Q[i].ri) Add(++R) ;
        while(R>Q[i].ri) Del(R--);
        while(L<Q[i].le) Del(L++);
        while(L>Q[i].le) Add(--L);

        ANS[Q[i].id]=ans;
    }
    for(int i=1;i<=q;i++) printf("%d\n",ANS[i]);
}

int main(){
    int n;scanf("%d",&n); B=(int)sqrt(n*1.0);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int q;scanf("%d",&q);
    for(int i=1;i<=q;i++){
        scanf("%d%d",&Q[i].le,&Q[i].ri);
        Q[i].id=i;
    }
    solve(q);
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值