您的位置:首页 > 其它

【BZOJ3585/3339】mex 莫队算法+分块

2017-05-04 09:24 134 查看

【BZOJ3585】mex

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

【BZOJ3339】Rmq Problem

题目一样,双倍经验

题解:依然直接上莫队+分块,发现虽然ai≤10^9,但是我们只需要判断它是否≥n,对于≥n的数我们直接领它为n就行了,因为n个自然数最多是0..n-1,出现了≥n的数就一定说明前面有空缺,所以不会对答案产生贡献

于是我们将自然数分块,维护块内不同自然数的个数和区间内自然数的出现次数,就没了~

又体会到了从0开始分块的美好~

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=200010;
int n,m,siz;
struct node
{
int qa,qb,org;
}q[maxn];
int v[maxn],ans[maxn],s[maxn],sk[maxn];
bool cmp(node a,node b)
{
if((a.qa-1)/siz==(b.qa-1)/siz)	return a.qb<b.qb;
return (a.qa-1)/siz<(b.qa-1)/siz;
}
int main()
{
scanf("%d%d",&n,&m);
siz=(int)sqrt((double)n);
int i,j;
for(i=1;i<=n;i++)	scanf("%d",&v[i]),v[i]=(v[i]<=n)?v[i]:n;
for(i=1;i<=m;i++)	scanf("%d%d",&q[i].qa,&q[i].qb),q[i].org=i;
sort(q+1,q+m+1,cmp);
int l=1,r=0;
for(i=1;i<=m;i++)
{
while(r<q[i].qb)	r++,sk[v[r]/siz]+=(s[v[r]]==0),s[v[r]]++;
while(r>q[i].qb)	s[v[r]]--,sk[v[r]/siz]-=(s[v[r]]==0),r--;
while(l>q[i].qa)	l--,sk[v[l]/siz]+=(s[v[l]]==0),s[v[l]]++;
while(l<q[i].qa)	s[v[l]]--,sk[v[l]/siz]-=(s[v[l]]==0),l++;
for(j=0;j*siz+siz-1<=n&&sk[j]==siz;j++);
for(j=j*siz;s[j]>0;j++);
ans[q[i].org]=j;
}
for(i=1;i<=m;i++)	printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: