【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

Sample Output

  1
  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 }
View Code

 

posted @ 2017-04-19 15:24  BearChild  阅读(257)  评论(0编辑  收藏  举报