BZOJ 3585 mex 莫队算法+分块

来源:互联网 发布:mac桌面路径命令 编辑:程序博客网 时间:2024/06/04 18:02

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))的。

第一,虽然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 500using 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;}


0 0
原创粉丝点击