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。
题解
这题首先在线是没法做的,所以我们可以考虑离线算法
解法1:莫队裸题,分块就好。
1 #include<map> 2 #include<queue> 3 #include<stack> 4 #include<cmath> 5 #include<ctime> 6 #include<cstdio> 7 #include<string> 8 #include<vector> 9 #include<cstdlib> 10 #include<cstring> 11 #include<iostream> 12 #include<algorithm> 13 #define LL long long 14 #define RE register 15 #define IL inline 16 using namespace std; 17 const int M=1000000; 18 const int N=50000; 19 const int Q=200000; 20 21 int cnt[M+5],ans; 22 int keep[Q+5]; 23 int n,m,a[N+5],tim; 24 struct query 25 { 26 int l,r,id; 27 }q[Q+5]; 28 bool comp(const query &a,const query &b){return a.l/tim==b.l/tim ? a.r<b.r:a.l<b.l;} 29 30 int main() 31 { 32 scanf("%d",&n); 33 tim=sqrt(n); 34 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 35 scanf("%d",&m); 36 for (int i=1;i<=m;i++) 37 { 38 scanf("%d%d",&q[i].l,&q[i].r); 39 q[i].id=i; 40 } 41 sort(q+1,q+m+1,comp); 42 int curl=0,curr=0,l,r; 43 for (int i=1;i<=m;i++) 44 { 45 l=q[i].l,r=q[i].r; 46 while (curl<l) {cnt[a[curl]]--;ans-=(cnt[a[curl++]]==0);} 47 while (curl>l) {cnt[a[--curl]]++;ans+=(cnt[a[curl]]==1);} 48 while (curr<r) {cnt[a[++curr]]++;ans+=(cnt[a[curr]]==1);} 49 while (curr>r) {cnt[a[curr]]--;ans-=(cnt[a[curr--]]==0);} 50 keep[q[i].id]=ans; 51 } 52 for (int i=1;i<=m;i++) printf("%d\n",keep[i]); 53 return 0; 54 }
莫队
解法2:排序+树状数组。
首先记录下每种颜色的下一种颜色所在的位置,将所有询问按照右端点进行排序。
左往右扫,扫过一个元素将该位置++,若有前驱,将前驱--。
扫到区间端点,答案为sum[r]-sum[l-1],记录一下就好。(其中sum为前缀和)
前缀和用树状数组实现。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 struct Node 7 { 8 int l,r,num; 9 }s[200001]; 10 int a[50001],ans[200001],n,m,c[100001],vis[1000001]; 11 bool cmp(Node a,Node b) 12 { 13 return (a.r<b.r||(a.r==b.r&&a.l<b.l)); 14 } 15 int getsum(int x) 16 { 17 int s=0; 18 while (x) 19 { 20 s+=c[x]; 21 x-=(x&(-x)); 22 } 23 return s; 24 } 25 void add(int x,int d) 26 { 27 while (x<=n) 28 { 29 c[x]+=d; 30 x+=(x&(-x)); 31 } 32 } 33 int main() 34 {int i,j; 35 cin>>n; 36 for (i=1;i<=n;i++) 37 { 38 scanf("%d",&a[i]); 39 } 40 cin>>m; 41 for (i=1;i<=m;i++) 42 { 43 scanf("%d%d",&s[i].l,&s[i].r); 44 s[i].num=i; 45 } 46 sort(s+1,s+m+1,cmp); 47 j=1; 48 for (i=1;i<=n+1;i++) 49 { 50 while (j<=m&&i>s[j].r) 51 { 52 ans[s[j].num]=getsum(s[j].r)-getsum(s[j].l-1); 53 j++; 54 } 55 if (i>n) break; 56 if (vis[a[i]]) 57 { 58 add(vis[a[i]],-1); 59 vis[a[i]]=i; 60 add(i,1); 61 } 62 else 63 { 64 vis[a[i]]=i; 65 add(i,1); 66 } 67 } 68 for (i=1;i<=m;i++) 69 printf("%d\n",ans[i]); 70 }
排序+树状数组
时间: 2024-10-05 23:57:11