BZOJ3585: mex

实际这题只需要考虑<=n的值

区间mex有两个经典做法,一个是莫队+对权值分块,另一个就是主席树
我们对1~i建立主席树,位置j维护1~i中,j最后一次出现的位置
查询 l   r 时,在第 r 棵主席树上找到第一个 < l 的值
O ( n l o g n )

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define pb push_back
using namespace std;

const int maxn = 410000;

int n,m,u;
int c[maxn];
struct node
{
    int x;
    int *i;
    friend inline bool operator <(const node x,const node y){return x.x<y.x;}
}a[maxn]; int To[maxn];
void Trans()
{
    for(int i=1;i<=n;i++) a[i].x=c[i],a[i].i=&c[i];
    sort(a+1,a+n+1);
    To[u=1]=a[0].x=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i].x==a[i-1].x+1) To[++u]=a[i].x;
        else if(a[i].x>a[i-1].x+1)
        {
            To[++u]=a[i-1].x+1;
            To[++u]=a[i].x;
        }
        (*a[i].i)=u;
    }
    To[++u]=a[n].x+1;
}

struct Segment
{
    int seg[maxn<<2];
    int loc,c;
    void pushup(int x){ seg[x]=min(seg[x<<1],seg[x<<1|1]); }
    void upd(const int x,const int l,const int r)
    {
        if(l==r) { seg[x]=c;return; }
        int mid=l+r>>1;
        if(loc<=mid) upd(x<<1,l,mid);
        else upd(x<<1|1,mid+1,r);
        pushup(x);
    }
    int query(int x,const int l,const int r)
    {
        if(l==r) return l;
        int mid=l+r>>1;
        return seg[x<<1]>=c?query(x<<1|1,mid+1,r):query(x<<1,l,mid);
    }
}Seg;

int op[maxn][2];
vector<int>V[maxn];
int ans[maxn];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&c[i]);
    Trans();

    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&op[i][0],&op[i][1]);
        V[op[i][1]].pb(i);
    }
    for(int i=1;i<=n;i++)
    {
        Seg.loc=c[i],Seg.c=i,Seg.upd(1,1,u);
        for(int j=0;j<(int)V[i].size();j++)
        {
            int qi=V[i][j];
            Seg.c=op[qi][0];
            ans[qi]=Seg.query(1,1,u);
        }
    }
    for(int i=1;i<=m;i++) printf("%d\n",To[ans[i]]);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/l_0_forever_lf/article/details/80222835
Mex
今日推荐