BZOJ3585: mex
http://www.lydsy.com/JudgeOnline/problem.php?id=3585
对于每次查询的区间[l,r],将权值分块,维护每一块内数字的出现次数,和每个权值的出现次数。因为mex值不会超过区间长度,这样我们就可以在O(√n)的时间内得到一个没有全被覆盖的区间,然后再O(√n)的时间暴力枚举当前块内的每个数,看是否出现过,即可得到答案。我们发现统计的信息可以在O(1)的时间内转移,于是用莫队算法来支持多次询问。
#include<bits/stdc++.h> using namespace std; const int maxn=200015,maxb=515; int n,m,siz,a[maxn]; struct Tquery{int idx,l,r;}Q[maxn]; bool cmp(Tquery x,Tquery y){ if (x.l/siz!=y.l/siz) return x.l/siz<y.l/siz; else return x.r<y.r; } void init(){ scanf("%d%d",&n,&m);siz=sqrt(n); for (int i=1;i<=n;++i) scanf("%d",&a[i]); for (int l,r,i=1;i<=m;++i){scanf("%d%d",&l,&r);Q[i]=(Tquery){i,l,r};} sort(Q+1,Q+m+1,cmp); } int ans[maxn],sum[maxn],have[maxb]; void solve(int k){ for (int i=Q[k-1].l;i<=Q[k].l-1;++i) if (a[i]<=n) if (!--sum[a[i]]) --have[a[i]/siz]; for (int i=Q[k-1].l-1;i>=Q[k].l;--i) if (a[i]<=n) if (!sum[a[i]]++) ++have[a[i]/siz]; for (int i=Q[k-1].r;i>=Q[k].r+1;--i) if (a[i]<=n) if (!--sum[a[i]]) --have[a[i]/siz]; for (int i=Q[k-1].r+1;i<=Q[k].r;++i) if (a[i]<=n) if (!sum[a[i]]++) ++have[a[i]/siz]; int pos;for (pos=0;have[pos]==siz;++pos); for (ans[Q[k].idx]=pos*siz;sum[ans[Q[k].idx]];++ans[Q[k].idx]); } void work(){ Q[0]=(Tquery){0,1,0};for (int i=1;i<=m;++i) solve(i); for (int i=1;i<=m;++i) printf("%d\n",ans[i]); } int main(){ init(); work(); return 0; }