题目:http://www.spoj.com/problems/DQUERY/en/

题意:给定一个数组,每次询问一个区间内有多少不同的元素

思路:本题用莫队或者主席树都可以,但是用树状数组离线更快。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

typedef long long ll;
const int N = 30010;
int bit[N], res[N*10];
int a[N], b[N], vis[N];
int n, m;
struct node
{
    int l, r, id;
} g[N*10];
bool cmp(node a, node b)
{
    return a.r < b.r;
}
void add(int i, int x)
{
    while(i <= n) bit[i] += x, i += i & -i;
}
int sum(int i)
{
    int s = 0;
    while(i > 0) s += bit[i], i -= i & -i;
    return s;
}
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i];
    sort(b+1, b+1+n);
    for(int i = 1; i <= n; i++) a[i] = lower_bound(b+1, b+1+n, a[i]) - b;
    scanf("%d", &m);
    for(int i = 1; i <= m; i++) scanf("%d%d", &g[i].l, &g[i].r), g[i].id = i;
    sort(g+1, g+1+m, cmp);
    memset(bit, 0, sizeof bit);
    memset(vis, 0, sizeof vis);
    int tot = 1;
    for(int i = 1; i <= n; i++)
    {
        if(vis[a[i]] == 0) add(i, 1), vis[a[i]] = i;
        else
        {
            add(vis[a[i]], -1);
            add(i, 1);
            vis[a[i]] = i;
        }
        while(tot <= m && g[tot].r == i)
            res[g[tot].id] = sum(g[tot].r) - sum(g[tot].l-1), tot++;
    }
    for(int i = 1; i <= m; i++) printf("%d\n", res[i]);
    return 0;
}