【BZOJ3339&&3585】mex [莫队][分块]
mex
Time Limit: 20 Sec Memory Limit: 128 MB[Submit][Status][Discuss]
Description
有一个长度为n的数组{a1,a2,...,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。
Input
第一行n,m。
第二行为n个数。
从第三行开始,每行一个询问l,r。
Output
一行一个数,表示每个询问的答案。
Sample Input
5 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5
Sample Output
1
2
3
0
3
2
3
0
3
HINT
1<=n,m<=200000, 0<=ai<=1e9
Solution
首先,权值>n的显然是没有用的,最多排满1~n。然后我们直接使用莫队,对权值分块,查询的时候看一下这个块里面权值数是否满了,即可做到O(sqrt(n))的查询。
Code
1 #include<iostream>
2 #include<string>
3 #include<algorithm>
4 #include<cstdio>
5 #include<cstring>
6 #include<cstdlib>
7 #include<cmath>
8 using namespace std;
9 typedef long long s64;
10
11 const int ONE = 200005;
12 const int INF = 2147483640;
13
14 int n,m,Q,num;
15 int a[ONE],block[ONE];
16 int Ans[ONE];
17 int C[ONE],Bc[ONE];
18
19 struct power
20 {
21 int id;
22 int l,r;
23 }oper[ONE];
24
25 int cmp(const power &a,const power &b)
26 {
27 if(block[a.l] != block[b.l]) return block[a.l] < block[b.l];
28 return a.r < b.r;
29 }
30
31 int get()
32 {
33 int res=1,Q=1; char c;
34 while( (c=getchar())<48 || c>57)
35 if(c=='-')Q=-1;
36 if(Q) res=c-48;
37 while((c=getchar())>=48 && c<=57)
38 res=res*10+c-48;
39 return res*Q;
40 }
41
42 void increa(int x) {if(x>n) return; C[x]++; if(C[x]==1) Bc[block[x]]++;}
43 void reduce(int x) {if(x>n) return; C[x]--; if(C[x]==0) Bc[block[x]]--;}
44
45 int Query()
46 {
47 int pos = 1;
48 for(int i=1;i<=num;i++)
49 if(Bc[i] < Q) {pos = i; break;}
50 for(int i=(pos-1)*Q+1;i<=n+1;i++)
51 if(!C[i])
52 return i-1;
53 }
54
55 int main()
56 {
57 n=get(); m=get();
58 Q = sqrt(n); num = (n-1)/Q+1;
59 for(int i=1;i<=n;i++)
60 a[i] = get()+1, block[i] = (i-1)/Q+1;
61 for(int i=1;i<=m;i++)
62 {
63 oper[i].id = i;
64 oper[i].l = get(); oper[i].r = get();
65 }
66
67 sort(oper+1, oper+m+1, cmp);
68
69 int l = 1, r = 0;
70 for(int i=1;i<=m;i++)
71 {
72 while(r < oper[i].r) increa(a[++r]);
73 while(oper[i].l < l) increa(a[--l]);
74 while(r > oper[i].r) reduce(a[r--]);
75 while(oper[i].l > l) reduce(a[l++]);
76 Ans[oper[i].id] = Query();
77 }
78
79 for(int i=1;i<=m;i++)
80 printf("%d\n", Ans[i]);
81 }