您的位置:首页 > 其它

BZOJ 3585 mex 莫队算法+分块

2017-03-25 19:51 302 查看
BZOJ 3585 mex

题目链接:右转进入题目

题目大意:给定n,m,n个数(0<=ai<=1e9),m个询问;

每次询问一段区间[L,R],在aL,a(L+1),,,,aR中第一个没有出现的自然数是多少?

n,m<=200010

题解:

裸的莫队算法。

但是这个题有一些值得注意的地方:

第零,由于莫队算法有nsqrt(n)次修改,m次询问,n和m同阶。

可以看到修改次数比询问次数多得多。

辣么说如果用线段树的话,修改和询问都是O(lng)的,那么复杂度就是O(n*sqrt(n)*lgn)的,会TLE。

所以改用分块。尽管询问是O(sqrt(n))的,但是修改是O(1)的。

因此改用分块就变成了O(n*sqrt(n))。就不会TLE了。

分块的做法是从第一块开始扫,扫到第一块不是每个点都是1的块,在块内暴力检查。

复杂度显然是O(sqrt(n))的。

4000
第一,虽然ai<=1e9,但是没有离散化的必要。更准确的说,对于>n的数字可以忽视。

因为>n的数字一定不会成为答案(想一想,为什么)。

一开始我还想离散化发现怎么也想不对,看了大神的blog才明白【捂脸

第二,绝大多数人下意识的当成了正整数,所以分块的时候就没有考虑0的情况。

但事实上有两种解决方法不需要重写,要么求mex的时候直接看一下a[0]的值,要么把读入的所有n个数字+1,最后查询得到的答案-1即可。

代码里用的前者。

附上代码:

//BZOJ 3585
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#define MAXN 200010
#define MAXM 200010
#define BLOCK_CNT 500
using namespace std;
int n,m,cnt[MAXN],a[MAXN];
struct block{
private:
int val[MAXN],belong[MAXN],sz,cnt,n;
int L[BLOCK_CNT],R[BLOCK_CNT],sumn[BLOCK_CNT];
public:
void init(int _n)
{
sz=sqrt(_n+0.5);
n=_n;cnt=n/sz+1;
belong[0]=0;
for(int i=1;i<=n;i++)
belong[i]=(i-1)/sz+1;
for(int i=1;i<=cnt;i++)
L[i]=(i-1)*sz+1,R[i]=i*sz;
}
void update(int pos,int v)
{
sumn[belong[pos]]+=v;
val[pos]+=v;
}
int mex()
{
if(val[0]==0) return 0;
int cur=1;
while(cur<=cnt&&sumn[cur]==sz) cur++;
for(int i=L[cur];i<=R[cur];i++)
if(val[i]==0) return i;
return 0;
}
}b;
struct query{
int l,r,id,pos;
}q[MAXM];
bool cmp(const query &q1,const query &q2)
{
if(q1.pos==q2.pos) return q1.r<q2.r;
else return q1.pos<q2.pos;
}
int ans[MAXM];
void add(int x)
{
if(a[x]>=n) return;
if(cnt[a[x]]==0) b.update(a[x],1);
cnt[a[x]]++;
}
void del(int x)
{
if(a[x]>=n) return;
cnt[a[x]]--;
if(cnt[a[x]]==0) b.update(a[x],-1);
}
int main()
{
scanf("%d%d",&n,&m);int sz;
sz=sqrt(n+0.5);b.init(n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;q[i].pos=q[i].l/sz;
}
sort(q+1,q+m+1,cmp);
int L=1,R=0;
for(int i=1;i<=m;i++)
{
while(L<q[i].l) del(L++);
while(L>q[i].l) add(--L);
while(R<q[i].r) add(++R);
while(R>q[i].r) del(R--);
ans[q[i].id]=b.mex();
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: