1878: [SDOI2009]HH的项链
Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 4420 Solved: 2199
[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
//离线算法的话,比较好写,树状数组,或线段树维护一个前缀和
在线算法听说是主席树,目前还不会,以后会了,一定更
离线树状数组,思路是,先对贝壳数组模拟一个链表,nex[i] 记录每个位置右边最近的与该位置贝壳种类相同的贝壳的位置。
然后,pos[i] 记录 i 种类的贝壳最靠左的位置,然后,对每个存在种类的贝壳的最靠左位置(就是pos[i]),建一个树状数组,位置上有最靠左的贝壳就是 1 ,否则是0,这样是为了统计区间内的种类数!
然后,所有查询按左端点排序,枚举左端点,靠前面的链表更新树状数组,求前缀和。
其实感觉最大的耗时在于对询问的排序。。。mlog(m)
1 /************************************************************** 2 Problem: 1878 3 User: happy_code 4 Language: C++ 5 Result: Accepted 6 Time:1780 ms 7 Memory:8908 kb 8 ****************************************************************/ 9 10 #include <iostream> 11 #include <stdio.h> 12 #include <string.h> 13 #include <algorithm> 14 using namespace std; 15 #define MXN 50005 16 #define MXM 200005 17 struct Que 18 { 19 int l,r; 20 int id; 21 int ans; 22 }q[MXM]; 23 24 int n,m; 25 int a[MXN]; 26 int pos[1000005]; 27 int nex[MXN]; 28 int tree[MXN]; 29 30 int lowbit(int x){return x&(-x);} 31 bool cmp1(const Que &a,const Que &b) 32 { 33 return a.l<b.l; 34 } 35 bool cmp2(const Que &a,const Que &b) 36 { 37 return a.id<b.id; 38 } 39 40 void update(int x,int k) 41 { 42 for (int i=x;i<=n;i+=lowbit(i)) 43 tree[i]+=k; 44 } 45 46 int query(int x) 47 { 48 int res=0; 49 for (int i=x;i>0;i-=lowbit(i)) 50 res+=tree[i]; 51 return res; 52 } 53 54 int main() 55 { 56 scanf("%d",&n); 57 for (int i=1;i<=n;i++) 58 scanf("%d",&a[i]); 59 for (int i=n;i>0;i--) 60 { 61 nex[i]=pos[a[i]]; 62 pos[a[i]]=i; 63 } 64 for (int i=0;i<1000005;i++) //初始化 65 if (pos[i]) update(pos[i],1); 66 67 68 scanf("%d",&m); 69 for (int i=0;i<m;i++) 70 { 71 scanf("%d%d",&q[i].l,&q[i].r); 72 q[i].id=i; 73 } 74 sort(q,q+m,cmp1); 75 76 int l=1; 77 for (int i=0;i<m;i++) 78 { 79 while (l<q[i].l) 80 { 81 if (nex[l]) update(nex[l],1); 82 l++; 83 } 84 q[i].ans = query(q[i].r)-query(q[i].l-1); 85 } 86 87 sort(q,q+m,cmp2); 88 for (int i=0;i<m-1;i++) 89 printf("%d ",q[i].ans); 90 printf("%d ",q[m-1].ans); 91 return 0; 92 }