n<=50000个数字,m<=200000个查询,每次问L到R之间有多少不同的数字。
这个询问可以离线的,为使L到R之间的数字只被算一次,可以从左往右扫,扫到一个数字就把上一个该数字出现的地方--,把现在这里++,为了配合这种操作,把所有询问按右端点排序,扫到一个地方就把该处所有右端点在这里的询问回答了。--和++只需树状数组计算前缀和即可。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 //#include<assert.h> 5 #include<math.h> 6 #include<algorithm> 7 //#include<iostream> 8 using namespace std; 9 10 int n,m; 11 #define maxn 50011 12 struct BIT 13 { 14 int a[maxn]; 15 BIT() {memset(a,0,sizeof(a));} 16 void add(int x,int v) {for (;x<=n;x+=x&-x) a[x]+=v;} 17 int query(int x) {int ans=0;for (;x;x-=x&-x) ans+=a[x];return ans;} 18 }t; 19 #define maxm 200011 20 struct Seg 21 { 22 int l,r,id; 23 bool operator < (const Seg &b) const {return r<b.r;} 24 }s[maxm]; 25 #define maxc 1000011 26 int pre[maxc],a[maxn],last[maxm]; 27 int main() 28 { 29 scanf("%d",&n); 30 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 31 scanf("%d",&m); 32 for (int i=1;i<=m;i++) scanf("%d%d",&s[i].l,&s[i].r),s[i].id=i; 33 sort(s+1,s+1+m); 34 memset(pre,0,sizeof(pre)); 35 for (int i=1,j=1;i<=n;i++) 36 { 37 if (pre[a[i]]) t.add(pre[a[i]],-1); 38 t.add(i,1); pre[a[i]]=i; 39 while (j<=m && s[j].r<=i) 40 last[s[j].id]=t.query(s[j].r)-t.query(s[j].l-1),j++; 41 } 42 for (int i=1;i<=m;i++) printf("%d ",last[i]); 43 return 0; 44 }