BZOJ3585 mex

分析

我们建立主席树,对于第\(r\)棵线段树每一个位置\(i\)存储的是数字\(i\)出现的最右端的位置。
那么对于区间询问\([l,r]\),就是找到第\(r\)棵线段树(注意不是差分)的第一个值小于\(l\)的位置(不可能大于\(r\))。
这个很容易,我们只需要维护区间最小值,询问时如果左区间的区间最小值小于\(l\)说明\(mex\)在左区间否则\(mex\)在右区间。
时间复杂度\(O(N \log V+M \log V)\),空间复杂度\(O(N \log V)\)

代码

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x){
    T data=0;
    int w=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=10*data+ch-'0',ch=getchar();
    return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;

const int MAXN=2e5+1,MAXM=6000000,MAXD=1e8;//5979470.5707972522261665749730809

int root[MAXN];
struct PreSegTree
{
    int cnt;
    int minv[MAXM];
    int L[MAXM],R[MAXM];
    
    void pushup(int o)
    {
        minv[o]=min(minv[L[o]],minv[R[o]]);
    }
    
    void insert(int&now,int l,int r,int p,int v)
    {
        minv[++cnt]=minv[now];
        L[cnt]=L[now],R[cnt]=R[now];
        now=cnt;
        if(l==r)
        {
            minv[now]=v;
            return;
        }
        int mid=(l+r)>>1;
        if(p<=mid)
            insert(L[now],l,mid,p,v);
        else
            insert(R[now],mid+1,r,p,v);
        pushup(now);
    }
    
    int query(int now,int l,int r,int x)
    {
        if(l==r)
            return l;
        int mid=(l+r)>>1;
        if(minv[L[now]]>=x) // 第一个小于x的位置 
            return query(R[now],mid+1,r,x);
        else
            return query(L[now],l,mid,x);
    }
}T;

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    int n,m;
    read(n);read(m);
    for(int i=1;i<=n;++i)
    {
        int a;
        read(a);
        root[i]=root[i-1];
        T.insert(root[i],0,MAXD,a,i);
    }
    while(m--)
    {
        int l,r;
        read(l);read(r);
        printf("%d\n",T.query(root[r],0,MAXD,l));
    }
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

Hint

尽管题目\(a\)范围为\(10^9\),但我MAXD1e9过不了开1e8却能过,不知道为什么。
或许题目有变动?反正我看不见这道权限题。

猜你喜欢

转载自www.cnblogs.com/autoint/p/9557249.html
Mex