[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 }

 

posted @ 2018-02-06 19:37  skylee03  阅读(103)  评论(0编辑  收藏  举报