- SPOJ 3267 DQUERY - D-query -
DQUERY - D-query
題意:
給定一個長度爲 n 的數組,對於之後的 m 次詢問,求詢問區間內不同元素的數目。
數據範圍:
1 ≤ n ≤ 30000,1 ≤ ai ≤ 106,1 ≤ m ≤ 200000
解題思路:
樹狀數組
對詢問按右區間從小到大排序
,掃描一遍數組,記錄每個元素最後一次出現的位置
,每遇到一個元素,若它在前面出現過,則在原來的位置-1,在現在的位置+1;若未在前面出現過,則直接在現在的位置+1,每次處理到右區間時,就計算一次該詢問的結果並保存在數組裏,最後按順序輸出即可。
代碼:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f
#define zero 1e-7
typedef long long ll;
const int N=1e6+5;
int n, m, a[N], mark[N], sum[N]={0}, ans[N]={0};
struct node {
int l, r, id;
}q[N];
bool cmp(node x, node y) {
return x.r<y.r;
}
int lowbit(int x) {
return x&(-x);
}
void add(int x, int c) {
while(x<=n) {
sum[x]+=c;
x+=lowbit(x);
}
return ;
}
int query(int x) {
int res=0;
while(x) {
res+=sum[x];
x-=lowbit(x);
}
return res;
}
int main() {
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
scanf("%d", &m);
for(int i=1; i<=m; i++) {
scanf("%d %d", &q[i].l, &q[i].r);
q[i].id=i;
}
sort(q+1, q+m+1, cmp);
memset(mark, -1, sizeof(mark));
int l=1;
for(int i=1; i<=m; i++) {
for(int j=l; j<=q[i].r; j++) {
if(mark[a[j]]!=-1) {
add(mark[a[j]], -1);
}
add(j, 1);
mark[a[j]]=j;//記錄a[j]最後一次出現的位置
}
l=q[i].r+1;
ans[q[i].id]=query(q[i].r)-query(q[i].l-1);
}
for(int i=1; i<=m; i++)
printf("%d\n", ans[i]);
return 0;
}