BZOJ 1878: [SDOI2009]HH的项链

1878: [SDOI2009]HH的项链

Time Limit: 4 Sec  Memory Limit: 64 MB
Submit: 3547  Solved: 1756
[Submit][Status][Discuss]

Description

HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此, 他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同 的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只好求助睿智的你,来解 决这个问题。

Input

第一行:一个整数N,表示项链的长度。 第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。 第三行:一个整数M,表示HH询问的个数。 接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。

Output

M行,每行一个整数,依次表示询问对应的答案。

Sample Input

6
1 2 3 4 3 5
3
1 2
3 5
2 6

Sample Output

2
2
4

HINT


对于20%的数据,N ≤ 100,M ≤ 1000;
对于40%的数据,N ≤ 3000,M ≤ 200000;
对于100%的数据,N ≤ 50000,M ≤ 200000。

Source

分析:

此题做法很多...这里主要贴上两种离线做法

No.1莫队

这就不用说了...和小Z的袜子做法相同...详见http://www.cnblogs.com/neighthorn/p/6202794.html

No.2树状数组

以前看过一道类似的题目(具体是啥不记得了)….所以这次还有点思路… 
我们考虑如果没有重复的数字直接算就好了…有重复的数字就应该每个数字只计算一次…怎么实现这种思想…. 
考虑对于一个询问,第一次出现的数字就是最靠左的数字,那么我们就把这个区间中第一次出现的数字设为1,求个前缀和就好了… 
所以说我们可以离线做…把所有询问按照左端点排序…对于当前的询问答案就直接计算前缀和就好…计算完之后,对于s[i].l~s[i+1].l-1这些数字,insert(j,-1),insert(nxt[j],1),这样就保证了对于当前的询问数组中设为1的数字都是不重复的….而且也不会漏掉一些数字…

感觉这种思想还是很常用的...

代码:

No.1莫队:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<map>
 6 //by NeighThorn
 7 using namespace std;
 8 
 9 const int maxn=50000+5,maxm=200000+5,blo=223;
10 
11 int n,m,tot,tmp,a[maxn],id[maxn],cnt[maxn];
12 
13 map<int,int> mp;
14 
15 struct M{
16     int l,r,num,ans;
17 }q[maxm];
18 
19 inline bool cmp1(M x,M y){
20     if(id[x.l]==id[y.l])
21         return x.r<y.r;
22     return x.l<y.l;
23 }
24 
25 inline bool cmp2(M x,M y){
26     return x.num<y.num;
27 }
28 
29 inline void change(int pos,int x){
30     if(cnt[a[pos]]==0&&cnt[a[pos]]+x==1)
31         tmp++;
32     else if(cnt[a[pos]]==1&&cnt[a[pos]]+x==0)
33         tmp--;
34     cnt[a[pos]]+=x;
35 }
36 
37 signed main(void){
38     tot=0;
39     scanf("%d",&n);
40     memset(cnt,0,sizeof(cnt)); 
41     for(int i=1,x;i<=n;i++){
42         scanf("%d",&x);
43         if(mp.find(x)==mp.end())
44             mp[x]=++tot;
45         a[i]=mp[x];
46     }scanf("%d",&m);
47     for(int i=1;i<=n;i++)
48         id[i]=(i-1)/blo+1;
49     for(int i=1;i<=m;i++)
50         scanf("%d%d",&q[i].l,&q[i].r),q[i].num=i;
51     sort(q+1,q+m+1,cmp1);tmp=0;
52     for(int i=1,l=1,r=0;i<=m;i++){
53         for(;l<q[i].l;l++)
54             change(l,-1);
55         for(;l>q[i].l;l--)
56             change(l-1,1);
57         for(;r<q[i].r;r++)
58             change(r+1,1);
59         for(;r>q[i].r;r--)
60             change(r,-1);
61         q[i].ans=tmp;
62     }
63     sort(q+1,q+m+1,cmp2);
64     for(int i=1;i<=m;i++)
65         printf("%d\n",q[i].ans);
66     return 0;
67 }
View Code

No.2树状数组:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 //by NeighThorn
 6 using namespace std;
 7 const int maxn=50000+5,maxm=1000000+5;
 8 int n,m,a[maxn],tr[maxn],pos[maxm],nxt[maxn];
 9 struct M{
10     int l,r,id,ans; 
11 }s[200000+5];
12 inline bool cmp1(M a,M b){
13     if(a.l==b.l)
14         return a.r<b.r;
15     return a.l<b.l;
16 }
17 inline bool cmp2(M a,M b){
18     return a.id<b.id;
19 }
20 inline void insert(int x,int y){
21     for(;x<=1000000;x+=x&(-x))
22         tr[x]+=y;
23 }
24 inline int query(int x){
25     int sum=0;
26     for(;x;x-=x&(-x))
27         sum+=tr[x];
28     return sum;
29 }
30 signed main(void){
31     scanf("%d",&n);memset(tr,0,sizeof(tr));
32     memset(pos,0,sizeof(pos));
33     for(int i=1;i<=n;i++){
34         scanf("%d",&a[i]);
35         if(pos[a[i]]==0)
36             insert(i,1),pos[a[i]]=i;
37         else
38             nxt[pos[a[i]]]=i,pos[a[i]]=i;
39     }
40     scanf("%d",&m);
41     for(int i=1;i<=m;i++)
42         scanf("%d%d",&s[i].l,&s[i].r),s[i].id=i;
43     sort(s+1,s+m+1,cmp1);s[0].l=0;
44     for(int i=1;i<=m;i++){
45         s[i].ans=query(s[i].r);
46         if(i<m&&s[i].l!=s[i+1].l)
47             for(int j=s[i].l;j<s[i+1].l;j++){
48                 insert(j,-1);
49                 if(nxt[j])
50                     insert(nxt[j],1);
51             }
52     }
53     sort(s+1,s+m+1,cmp2);
54     for(int i=1;i<=m;i++)
55         printf("%d\n",s[i].ans);
56     return 0;
57 }
58 
View Code

by NeighThorn

posted @ 2016-12-20 16:16  NeighThorn  阅读(160)  评论(0编辑  收藏  举报