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
",ans[i]);
}
int main(){
    init();
    work();
    return 0;
}
my code
原文地址:https://www.cnblogs.com/iamCYY/p/4719921.html