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
数据规模和约定
对于100%的数据:
1<=n,m<=200000
0<=ai<=109
1<=l<=r<=n
对于30%的数据:
1<=n,m<=1000
Source
By 佚名提供
显而易见我们可以发现,大于
的数是不会对答案产生贡献的。
我们将大于
的数变为
统计答案。
将
~
的数分块,每块记录一个数字表示块内出现过的自然数的个数。
然后上莫队暴力维护即可。
#include<bits/stdc++.h>
using namespace std;
int n , Q , k;
int a[201000] , belong[201000];
int flag[201000];
int sum[500] , t;
struct data{
int l , r , id;
}q[201000];
int read()
{
int sum = 0;char c = getchar();bool flag = true;
while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}
while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();
if(flag) return sum;
else return -sum;
}
bool mycmp(data a,data b)
{
return belong[a.l] < belong[b.l]||
(belong[a.l] == belong[b.l] && a.r < b.r);
}
void init()
{
n = read();Q = read();
for(int i = 1;i <= n;++i)
{
a[i] = read();
if(a[i] > n) a[i] = n;
}
for(int i = 1;i <= Q;++i)
q[i].l = read() , q[i].r = read() , q[i].id = i;
k = sqrt(n);
if(k * k < n) t = k + 1,sum[t] = k*k + k - n;
else t = k;
for(int i = 1,j = k,t = 1;i <= n;i += k,j += k,t++)
if(j <= n) for(int x = i;x <= j;++x) belong[x] = t;
else for(int x = i;x <= n;++x) belong[x] = t;
sort(q + 1,q + Q + 1,mycmp);
return;
}
void add(int x)
{
x = a[x];
if(flag[x] == 0) sum[belong[x]]++;
flag[x]++;
return;
}
void dele(int x)
{
x = a[x];
if(flag[x] == 1) sum[belong[x]]--;
flag[x]--;
return;
}
int print()
{
if(!flag[0]) return 0;
int i;
for(i = 1;i <= t;++i)
if(sum[i] != k)
break;
for(int j = (i - 1) * k + 1;i <= i * k;++i)
if(!flag[i]) return i;
}
int out[201000];
void solve()
{
int l = 1,r = 0;
for(int i = 1;i <= Q;++i)
{
while(l > q[i].l) l-- , add(l);
while(r < q[i].r) r++ , add(r);
while(l < q[i].l) dele(l) , l++;
while(r > q[i].r) dele(r) , r--;
out[q[i].id] = print();
}
for(int i = 1;i <= Q;++i)
printf("%d\n",out[i]);
return;
}
int main()
{
init();
solve();
return 0;
}