[BZOJ3585]mex
题目大意:
给定一个长度为$n(n\leq2\times10^5)$的数列$A$。$m$次询问,每次询问${\rm mex}(\{A_l,\ldots,A_r\})$。
思路:
莫队。
维护每个数出现的次数$cnt[x]$。
加入一个数$x$时,$cnt[x]--$。若$cnt[x]=0$,则对当前${\rm mex}$取$\min$。
删除一个数$x$时,$cnt[x]++$。若$cnt[{\rm mex}]\neq0$,则暴力计算新的${\rm mex}$。
注意每次移动查询区间时要先加入再删除,不然会导致$cnt[x]$为负。
1 #include<cmath> 2 #include<cstdio> 3 #include<cctype> 4 #include<algorithm> 5 inline int getint() { 6 register char ch; 7 while(!isdigit(ch=getchar())); 8 register int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int N=200001; 13 int mex,a[N],bel[N],cnt[N],ans[N]; 14 struct Query { 15 int l,r,id; 16 bool operator < (const Query &another) const { 17 return bel[l]<bel[another.l]||(bel[l]==bel[another.l]&&bel[r]<bel[another.r]); 18 } 19 }; 20 Query q[N]; 21 inline void ins(const int &x) { 22 if(!~a[x]) return; 23 cnt[a[x]]++; 24 while(cnt[mex]) mex++; 25 } 26 inline void del(const int &x) { 27 if(!~a[x]) return; 28 if(!--cnt[a[x]]) mex=std::min(mex,a[x]); 29 } 30 int main() { 31 const int n=getint(),m=getint(),block=sqrt(n); 32 for(register int i=0;i<n;i++) { 33 if((a[i]=getint())>=n) a[i]=-1; 34 bel[i]=i/block; 35 } 36 for(register int i=0;i<m;i++) { 37 const int l=getint()-1,r=getint()-1; 38 q[i]=(Query){l,r,i}; 39 } 40 std::sort(&q[0],&q[m]); 41 for(register int i=0,l=0,r=-1;i<m;i++) { 42 while(l>q[i].l) ins(--l); 43 while(r<q[i].r) ins(++r); 44 while(l<q[i].l) del(l++); 45 while(r>q[i].r) del(r--); 46 ans[q[i].id]=mex; 47 } 48 for(register int i=0;i<m;i++) { 49 printf("%d\n",ans[i]); 50 } 51 return 0; 52 }