【题目地址】点击打开链接
【题目大意】
给出长度为N的数字序列A[],Q个提问,每次询问为l,r,输出区间[l,r]的mex。
mex{S}定义为自然数(包括0)中最小的,不在集合S中的值。
N,Q,A[]范围均为20w级别
(尼玛,题目名字跟意思毫无关系啊有木有)
【分析】
我们可以预处理区间[1,x]的mex,用数组Mex[x]记录。 并用一棵线段树来保存区间信息,域即为mex值。
我们从左往右扫描A[]数组,扫描到位置i时,令j为值A[i]下一次出现的位置。
那么我们删除位置i的值的影响时,区间[i+1,j-1]之间的mex都要更新为,mex=min(mex,A[i])。
但如果直接更新,时间无法承受,注意到mex函数是单调不降的,所以我们可以二分求到mex值大于A[i]的位置。直接在线段树中修改区间。
删除位置i的值的影响后,所有以i+1为区间左端点的询问都是最新的。
可以直接用右端点从线段树的相应位置获取答案了。
【代码】
/*************************
ID:Ciocio
LANG:C++
DATE:2014-1-29
TASK:Mex
*************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
using namespace std;
#define MAXN 200000
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rrep(i,b,a) for(int i=b;i>=a;--i)
#define Mid ((Left+Right)>>1)
#define lc (id<<1)
#define rc ((id<<1)|1)
int N,Q,p,q,ad;
int A[MAXN+10],Mex[MAXN+10];
int Last[MAXN+10],Next[MAXN+10];
struct wjj{
int l,r;
int rank,ans;
}Que[MAXN+10];
struct SegTree{
int Key[(MAXN+10)<<2];
void init(){
memset(Key,-1,sizeof Key);
}
void putdown(int id){
Key[lc]=
Key[rc]=Key[id];
Key[id]=-1;
}
void insert(int id,int Left,int Right){
if(p<=Left&&Right<=q){
Key[id]=ad;
return;
}
if(Key[id]!=-1) putdown(id);
if(!(q<Left||Mid<p)) insert(lc,Left,Mid);
if(!(q<Mid+1||Right<p)) insert(rc,Mid+1,Right);
}
int find(int id,int Left,int Right){
if(Key[id]!=-1) return Key[id];
if(p<=Mid) return find(lc,Left,Mid);
else return find(rc,Mid+1,Right);
}
}Tree;
bool cmp1(const wjj& A,const wjj& B){
return (A.l<B.l)||(A.l==B.l&&A.r<B.r);
}
bool cmp2(const wjj& A,const wjj& B){
return A.rank<B.rank;
}
void _read(int& x){
char tt=getchar();
while(tt<'0'||'9'<tt) tt=getchar();
for(x=0;'0'<=tt&&tt<='9';x=(x<<1)+(x<<3)+tt-'0',tt=getchar());
}
void _init(){
_read(N);_read(Q);
rep(i,1,N) _read(A[i]);
rep(i,1,Q){
_read(Que[i].l);
_read(Que[i].r);
Que[i].rank=i;
}
sort(Que+1,Que+Q+1,cmp1);
}
void _change(int loc){
int l=loc+1,r=Next[loc]-1;
int ans=-1;
q=
r=r>0?r:N;
while(l<=r){
int m=(l+r)>>1;
p=m;
if(Tree.find(1,0,MAXN+1)>=A[loc]){
ans=m;
r=m-1;
}
else
l=m+1;
}
p=ans;
if(ans==-1||Tree.find(1,0,MAXN+1)<=A[loc]) return;
ad=A[loc];
Tree.insert(1,0,MAXN+1);
}
void _solve(){
//get Mex
set <int> Set;
rep(i,0,MAXN+1) Set.insert(i);
rep(i,1,N){
Set.erase(A[i]);
Mex[i]=*Set.begin();
}
//build segtree
Tree.init();
Mex[0]=-1;
rep(i,1,N){
if(Mex[i]!=Mex[i-1]){
int j=i;
while(Mex[j+1]==Mex[j]&&j+1<=N) j++;
p=i;q=j;ad=Mex[i];
Tree.insert(1,0,MAXN+1);
i=j;
}
}
//get relationship of A's key
rrep(i,N,1){
Next[i]=Last[A[i]];
Last[A[i]]=i;
}
//deal with the query
int now=1;
rep(i,1,Q){
while(now!=Que[i].l) _change(now++);
p=Que[i].r;
Que[i].ans=Tree.find(1,0,MAXN+1);
}
//print
sort(Que+1,Que+Q+1,cmp2);
rep(i,1,Q)
printf("%d\n",Que[i].ans);
}
int main(){
_init();
_solve();
return 0;
}