# Lightoj1188 Fast Queries(树状数组离线)

#### 题意

给出n个数，Q次询问l，r表示数组l到r区间内有多少种数字。


#### 思路

离线处理每个区间，把区间按照r的值从小到大排序。用vis[...]数组记录每个数前面出现的最近的位置。处理到位置i时，如果前面出现过a[i],


const int maxn = 1e6 + 1234;
struct Querys {
int l, r, idx;
}p[maxn];
bool cmp(const Querys& A, const Querys& B) {
return A.r < B.r;
}
int b[maxn], ans[maxn], vis[maxn], c[maxn];
int n, q;
while(i <= n) {
b[i] += v;
i += lowbit(i);
}
}
int sum(int i) {
int res = 0;
while(i > 0) {
res += b[i];
i -= lowbit(i);
}
return res;
}
int main(int argc, const char * argv[])
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);

int kase;cin >> kase;
while(kase--) {
scanf("%d%d", &n, &q);
for (int i = 1;i <= n;++i)
scanf("%d", &c[i]);
memset(vis, 0, sizeof vis);
memset(b, 0, sizeof b);
for (int i = 1;i <= q;++i) {
scanf("%d%d", &p[i].l, &p[i].r);
p[i].idx = i;
}
sort(p + 1, p + 1 + q, cmp);
// for (int i = 1;i <= q;++i)
//     printf("[l = %d, r = %d]\n", p[i].l, p[i].r);
int cnt = 1;
for (int i = 1;i <= n;++i) {
vis[c[i]] = i;
while(cnt <= q && p[cnt].r == i) {
ans[p[cnt].idx] = sum(p[cnt].r) - sum(p[cnt].l - 1);
cnt++;
}
if (cnt > q) break;
}
printf("Case %d:\n", ++nCase);
for (int i = 1;i <= q;++i)
printf("%d\n", ans[i]);
}

// showtime;
return 0;
}