【题解】P4137 Rmq Problem(莫队)
其实这道题根本就不用离散化!
因为显然有(mex)值是(le 2 imes 10^5)的,所以对于大于(2 imes 10^5)的数我们可以忽略。
然后直接莫队算就是的,开一个(2e5)的桶
- 若一个比答案小的值的桶为(0)了:答案更新为它
- 若这个(mex)的桶突然有值了:暴力枚举答案变大,第一个桶里没值的就是答案,更新。
有小伙伴会问,这复杂度不上天了?其实不然。移动(ans)的总复杂度(好像)是(O(nsqrt n))的,因为:
-
当区间长度增大时,(ans)的移动是均摊(O( ext{区间长度}))的(最坏情况(好像)是加进来的数就变成了一个递增序列)。
-
当区间减小时,(ans)是直接更新的。所以(ans)指针的移动和(L,R)指针的移动次数是同级的。
由于莫队中,区间减小增大不是交替的(不存在(L)动一次交替然后(R)动一次)(都是一个动完再动另外一个),所以最终复杂度(O(nsqrt n)),实际上(貌似)吊打(O(n log n))
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=2e5+5;
int be[maxn];
int data[maxn];
int s[maxn];
int n,N,ans,m;
struct Q{
int l,r,id;
Q(){l=r=id=0;}
Q(const int&a,const int&b,const int&c){l=a;r=b;id=c;}
inline bool operator <(const Q&a)const{return be[l]==be[a.l]?(be[l]&1?r<a.r:r>a.r):(l<a.l);}
}q[maxn];
inline void add(const int&pos,const int&tag){
if(data[pos]>maxn) return;
s[data[pos]]+=tag;
const int k=s[data[pos]];
if(k==0&&ans> data[pos]) ans=data[pos];
if(k==1&&ans==data[pos])
while(++ans) if(!s[ans]) return;
}
int main(){
n=qr(),m=qr();
N=sqrt(n)+1;
for(register int t=1;t<=n;++t) be[t]=(t-1)/N+1;
for(register int t=1;t<=n;++t) data[t]=qr();
for(register int t=1,t1,t2;t<=m;++t) t1=qr(),t2=qr(),q[t]=Q(t1,t2,t);
sort(q+1,q+m+1);
register int L=1,R=0;
for(register int t=1;t<=m;++t){
while(L<q[t].l) add(L++,-1);
while(L>q[t].l) add(--L, 1);
while(R<q[t].r) add(++R, 1);
while(R>q[t].r) add(R--,-1);
be[q[t].id]=ans;
}
for(register int t=1;t<=m;++t) printf("%d
",be[t]);
return 0;
}