[校内NOIP2018模拟20181027] mex

题目描述

给定一个长度为\(n\)的数列\(A\),数列的第\(i\)的元素是\(A_i\)(从\(1\)开始编号)。你需要回答\(q\)个询问,每个询问的参数是一个二元组\((l,r)\)\(l\leq r\)),表示查询\(mex(\{A_l,A_{l+1},...,A_r\})\)

所谓\(mex\),就是\(SG\)定理中的那个函数,也就是"Minimum Exclusive"的缩写。对一个非负整数组成的集合\(S\)\(mex(S)\)的值等于最小的不属于集合\(S\)的非负整数。

输入格式

输入文件第一行包含\(2\)个空格隔开的正整数\(n\)\(q\),代表序列A的长度和询问个数。

输入文件第二行包含\(n\)个空格隔开的非负整数,第\(i\)个数表示\(A_i\)的值。

接下来\(q\)行,每行包含\(2\)个空格隔开的正整数\(l\)\(r\)\(1\leq l \leq r\leq n\)),表示一个查询的参数。

输出格式

输出文件应当包含\(q\)行,每行一个正整数,表示输入文件中对应询问的答案。

样例数据

Input

7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7

output

3
0
3
2
4

\(1\)个询问: \(mex(\{0,2,1\})=3\)

\(2\)个询问: \(mex(\{2,1\})=0\)

\(3\)个询问: \(mex(\{0,2,1,0\})=3\)

\(4\)个询问: \(mex(\{1,0,1,3\})=2\)

\(5\)个询问: \(mex(\{2,1,0,1,3,2\})=4\)

数据规模与约定

数据中无向图无自环;

对于\(10\%\) 的数据,满足\(n,q \leq 100\)

对于\(30\%\) 的数据,满足\(n,q \leq 50000\)

对于\(60\%\) 的数据,满足\(n,q \leq 200000\); \(0\leq A_i\leq 200000\)

对于\(100\%\) 的数据,满足\(n,q \leq 1000000\); \(0\leq A_i\leq 1000000\); \(A_i\)均为非负整数; \(1\leq l\leq r\leq n\); \(l\)\(r\)均为正整数; 数据有一定梯度。

时间限制:\(1\text{s}\)

空间限制:\(128\text{MB}\)

Solution

这道题目就是要找不在这段区间里面的最小整数,所以对于数字的存在性,显然就是套路题了。

建一个权值线段树,维护一下每个数字最后一次出现的位置。把询问离线到\(r\)上,然后从左往右扫,更新线段树。对于\(r\)在这个点的询问,在线段树里面二分,只要左子树存在一个数比\(l\)小就去左子树,否则去右子树。然后就就结束了。时间复杂度\(O(q\log n)\)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define lc o<<1
#define rc o<<1|1
using namespace std;
typedef long long ll;typedef unsigned long long ull;
namespace io{
    const int SIZE=(1<<21)+1;char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];int f,qr;
    #define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++)
    inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}
    inline void putc(char x){*oS++=x;if(oS==oT)flush();}
    template<class I>inline void read(I &x){for(f=1,c=gc();c<'0'||c>'9';c=gc())if(c=='-')f=-1;for(x=0;c<='9'&&c>='0';c=gc())x=x*10+(c&15);x*=f;}
    template<class I>inline void write(I x){if(!x)putc('0');if(x<0)putc('-'),x=-x;while(x)qu[++qr]=x%10+'0',x/=10;while(qr)putc(qu[qr--]);}
    inline void print(const char *s){while(*s!='\0')putc(*s++);}
    inline void scan(char *s){for(c=gc();c<=' ';c=gc());for(;c>' ';c=gc())*(s++)=c;*s='\0';}
    struct Flusher_{~Flusher_(){flush();}}io_flusher_;
}//orz laofudasuan
using io::read;using io::write;using io::putc;
template<typename A,typename B>inline bool SMAX(A&a,const B&b){return a<b?a=b,1:0;}
template<typename A,typename B>inline bool SMIN(A&a,const B&b){return b<a?a=b,1:0;}

const int N=1e6+7,INF=0x3f3f3f3f;
int n,m,Q,x,y,a[N],pre[N];
struct Question{int l,r,id,ne,ans;inline bool operator<(const Question&a)const{return id<a.id;}}q[N];int head[N],tot;
inline void Add(int x,Question r){q[++tot]=r;q[tot].ne=head[x];head[x]=tot;}

struct Node{int val;}t[N<<2];
inline void pushup(int o){t[o].val=min(t[lc].val,t[rc].val);}
inline void Update(int o,int L,int R,int x,int k){if(L==R)return (void)(t[o].val=k);int M=(L+R)>>1;x<=M?Update(lc,L,M,x,k):Update(rc,M+1,R,x,k);pushup(o);};
inline int Query(int o,int L,int R,int l){if(L==R)return L;int M=(L+R)>>1;if(t[lc].val<l)return Query(lc,L,M,l);else return Query(rc,M+1,R,l);}

int main(){
    read(n),read(Q);
    for(register int i=1;i<=n;++i)read(a[i]),SMAX(m,a[i]);++m;
    for(register int i=1;i<=Q;++i)read(x),read(y),Add(y,Question{x,y,i});
    for(register int i=1;i<=n;++i){
        Update(1,0,m,a[i],i);
        for(register int j=head[i];j;j=q[j].ne){
            Question p=q[j];
            q[j].ans=Query(1,0,m,p.l);
        }
    }
    for(register int i=1;i<=Q;++i)write(q[i].ans),putc('\n');
}

猜你喜欢

转载自www.cnblogs.com/hankeke/p/20181027-mex.html
Mex