BZOJ1878: [SDOI2009]HH的项链

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\n",last[i]);
43     return 0;
44 }
View Code

 

posted @ 2017-10-18 06:47  Blue233333  阅读(112)  评论(0编辑  收藏  举报