【BZOJ3585】【JZOJ3547】【luoguP4137】mex

problem

Description

有一个长度为n的数组{a1,a2,…,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。

Input

第一行n,m。

第二行为n个数。

从第三行开始,每行一个询问l,r。

Output

一行一个数,表示每个询问的答案。

Sample Input

5 5

2 1 0 2 1

3 3

2 3

2 4

1 2

3 5

Sample Output

1

2

3

0

3

Data Constraint

对于30%的数据:

1<=n,m<=1000

对于100%的数据:

1<=n,m<=200000

0<=ai<=10^9

1<=l<=r<=n


analysis

  • BZOJ把这题给删掉了……

  • 求mex的经典数据结构主席树

  • 用主席树维护 [ 1 , x ] 区间每个权值最后一次出现的位置(也就是最靠右的位置)

  • 查询一个二分,如果区间内所有数的最右位置都 L 以内就在右边,否则在左边


code

#include<bits/stdc++.h>
#define MAXN 200001
#define INF 1000000007
#define fo(i,a,b) for (int i=a;i<=b;i++)

using namespace std;

int lson[MAXN*30],rson[MAXN*30],mn[MAXN*30];
int root[MAXN];
int n,m,tot;

int read()
{
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0' || '9'<ch)
    {
        if (ch=='-')f=-1;
        ch=getchar();   
    }
    while ('0'<=ch && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

void update(int &t,int old,int l,int r,int x,int y)
{
    t=++tot;
    lson[t]=lson[old],rson[t]=rson[old],mn[t]=mn[old];
    if (l==r)
    {
        mn[t]=y;
        return;
    }
    int mid=(l+r)/2;
    if (x<=mid)update(lson[t],lson[old],l,mid,x,y);
    else update(rson[t],rson[old],mid+1,r,x,y);
    mn[t]=min(mn[lson[t]],mn[rson[t]]);
}

int query(int t,int l,int r,int x)
{
    if (l==r)return l;
    int mid=(l+r)/2;
    if (mn[lson[t]]<x)return query(lson[t],l,mid,x);
    else return query(rson[t],mid+1,r,x);
}

int main()
{
    //freopen("readin.txt","r",stdin);
    n=read(),m=read();
    fo(i,1,n)
    {
        int x=read();
        update(root[i],root[i-1],1,n+1,x+1,i);
    }
    while (m--)
    {
        int l=read(),r=read();
        printf("%d\n",query(root[r],1,n+1,l)-1);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/enjoy_pascal/article/details/80783337