1878: [SDOI2009]HH的项链
Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 4268 Solved: 2142
[Submit][Status][Discuss]
Description
HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一
段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此他的项链变得越来越长。有一天,他突然提出了一
个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只
好求助睿智的你,来解决这个问题。
Input
第一行:一个整数N,表示项链的长度。
第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。
第三行:一个整数M,表示HH询问的个数。
接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
N ≤ 50000,M ≤ 200000。
Output
M行,每行一个整数,依次表示询问对应的答案。
Sample Input
6
1 2 3 4 3 5
3
1 2
3 5
2 6
1 2 3 4 3 5
3
1 2
3 5
2 6
Sample Output
2
2
4
2
4
HINT
Source
此题一看就知道在线处理没戏,于是我们想到按询问左端点的顺序离线处理。
我们利用前缀和来求区间元素种类。
对于一个颜色a[i],我们记录下一个与它相同的颜色的位置。首先我们将所有颜色第一次出现的位置+1,随后我们从左向右扫,当扫到颜色a[i]时,将next[a[i]]+1。
对于每一个询问,我们计算sum[ask[i].r]-sum[ask[i].l-1]的值,可以用树状数组维护。但需要注意的是询问的左边界的颜色如果在区间中出现会被多算一次,需要处理。
代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 int n,m; 9 int a[50005]; 10 int next[50005],before[50005]; 11 int temp[1000005]; 12 struct data 13 { 14 int l,r,id,an; 15 }ask[200005]; 16 int sum[50005]; 17 int lowbit(int x){return x&(-x);} 18 void update(int now) 19 { 20 for(int i=now;i<=n;i+=lowbit(i)) sum[i]++; 21 } 22 int query(int now) 23 { 24 int ans=0; 25 for(int i=now;i;i-=lowbit(i)) ans+=sum[i]; 26 return ans; 27 } 28 bool cmp(data t1,data t2) 29 { 30 return t1.l<t2.l; 31 } 32 bool cmp1(data t1,data t2) 33 { 34 return t1.id<t2.id; 35 } 36 int main() 37 { 38 scanf("%d",&n); 39 for(int i=1;i<=n;i++) 40 { 41 scanf("%d",&a[i]); 42 if(!temp[a[i]])update(i); 43 before[i]=temp[a[i]]; 44 next[temp[a[i]]]=i; 45 temp[a[i]]=i; 46 } 47 scanf("%d",&m); 48 for(int i=1;i<=m;i++) 49 { 50 scanf("%d%d",&ask[i].l,&ask[i].r); 51 ask[i].id=i; 52 } 53 sort(ask+1,ask+m+1,cmp); 54 int now=1; 55 for(int i=1;i<=n;i++) 56 { 57 if(next[i]) update(next[i]); 58 while(ask[now].l==i) 59 { 60 ask[now].an=query(ask[now].r)-query(ask[now].l-1); 61 if(next[i]<=ask[now].r&&next[i]!=0) ask[now].an--; 62 now++; 63 } 64 } 65 sort(ask+1,ask+m+1,cmp1); 66 for(int i=1;i<=m;i++) printf("%d ",ask[i].an); 67 return 0; 68 }