【bzoj3585】mex 分块+莫队算法

因为在线不太可搞,所以考虑离线。

首先,按照莫队的方式对操作排序,对权值分块,维护一下每个块出现的个数。

每次询问,找到第一个没有铺满的块,在下一个块内暴力找即可。


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 200010  
 
using namespace std;
 
struct yts
{
    int l,r,id;
}q[maxn];
 
int ans[maxn];
int pos[maxn],bel[maxn],L[maxn],R[maxn],w[maxn];
int num[maxn];
int a[maxn];
int n,m,tot,block,mx;
 
bool cmp(yts x,yts y)
{
    if (pos[x.l]!=pos[y.l]) return x.l<y.l;
    return x.r<y.r;
}
 
int query()
{
    int i;
    for (i=1;i<=tot;i++) if (num[i]!=block) break;
    int j;
    for (j=L[i];j<=R[i];j++) if (!w[j]) break;
    return j;
}
 
void del(int x)
{
    if (x>n) return;
    w[x]--;
    if (w[x]==0) num[bel[x]]--;
}
 
void add(int x)
{
    if (x>n) return;
    if (w[x]==0) num[bel[x]]++;
    w[x]++;
}
 
void solve()
{
    int l=1,r=0;
    for (int i=1;i<=m;i++)
    {
        while (l<q[i].l) del(a[l++]);
        while (r>q[i].r) del(a[r--]);
        while (l>q[i].l) add(a[--l]);
        while (r<q[i].r) add(a[++r]);
        ans[q[i].id]=query();
    }
}
 
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    block=(int)sqrt(n);
    for (int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
    tot=n/block+1;
    for (int i=0;i<=n;i++)
    {
        bel[i]=i/block+1;
        if (!L[bel[i]]) L[bel[i]]=i;
        R[bel[i]]=i;
    }
    L[1]=0;
    for (int i=1;i<=m;i++) {scanf("%d%d",&q[i].l,&q[i].r);q[i].id=i;}
    sort(q+1,q+m+1,cmp);
    solve();
    for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}


你可能感兴趣的:(【bzoj3585】mex 分块+莫队算法)