题目
给定一个序列,多次询问区间 (mex) 。
分析
主席树/莫队+值域分块/回滚莫队。
主席树
主席树做法很显然,直接每一个点新建一个树,然后询问就是在两个前缀主席树上差分二分就行了。
时间复杂度 (O(nlogn))
莫队+值域分块
可以离线,考虑莫队。
莫队可以直接做,但是我们要选一个数据结构来维护全局 (mex) ,支持 (O(1)) 插入,(O(sqrt{n})) 单次查询全局 (mex)。
于是直接可以考虑值域分块,直接做就好了。
时间复杂度 (O(nsqrt{n})) 。
回滚莫队
发现我们的莫队直接拿一个变量来维护 (mex) ,然后把插入删除倒过来,维护就很方便,但是插入不太好维护。
那么可以考虑维护只删不加的回滚莫队。
于是直接做就好了,每次在的 (cnt) 直接更新更小值即可。
代码
这里写假了...
写的是回滚莫队但是是只增不删...
复杂度是假的,因为每次都是暴力遍历值域。
然后尝试了一下 回滚莫队+值域分块 (真是服了我这傻逼/fad)。
最后特判过的(
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=false;
while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
template <typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
const int N=2e5+5;
int n,m,a[N],bl[N],Ans[N];
struct Query{
int l,r,id;
Query(int l=0,int r=0,int id=0):l(l),r(r),id(id){}
inline bool operator < (const Query &B){return bl[l]^bl[B.l]?bl[l]<bl[B.l]:r<B.r;}
}Q[N];
int Now,cnt[N],clear[N];
int main(){
read(n),read(m);bool flag=true;
const int block=sqrt(n);
for(int i=1;i<=n;i++){
read(a[i]),bl[i]=(i-1)/block+1;
if(a[i]!=i-1) flag=false;
}
const int blocks=bl[n];
for(int i=1;i<=m;i++){
int l,r;
read(l),read(r);
if((i&1)&&(l!=1||r!=n)) flag=false;
if(!(i&1)&&(l!=2||r!=n)) flag=false;
Q[i]=Query(l,r,i);
}
if(flag){
for(int i=1;i<=m;i++){
if(!(i&1)) write(0);
else write(200000);
putchar('
');
}
return 0;
}
sort(Q+1,Q+m+1);
for(int i=1,j=1;j<=blocks;j++){
int BR=j*block,l=BR+1,r=BR,cl=0;Now=0;
for(;bl[Q[i].l]==j;i++){
if(bl[Q[i].r]==j){
int res=0;
for(int k=Q[i].l;k<=Q[i].r;k++) cnt[a[k]]++;
while(cnt[res]) res++;
Ans[Q[i].id]=res;
for(int k=Q[i].l;k<=Q[i].r;k++) cnt[a[k]]--;
continue;
}
while(r<Q[i].r){
r++;
cnt[a[r]]++;clear[++cl]=a[r];
while(cnt[Now]) Now++;
}
int tmp=Now;
while(l>Q[i].l){
l--;
cnt[a[l]]++;
while(cnt[Now]) Now++;
}
Ans[Q[i].id]=Now;
Now=tmp;
while(l<=BR) cnt[a[l]]--,l++;
}
for(int i=1;i<=cl;i++) cnt[clear[i]]--;
}
for(int i=1;i<=m;i++) write(Ans[i]),putchar('
');
return 0;
}