【题解】P4137 Rmq Problem(莫队)
其实这道题根本就不用离散化!
因为显然有\(mex\)值是\(\le 2\times 10^5\)的,所以对于大于\(2\times 10^5\)的数我们可以忽略。
然后直接莫队算就是的,开一个\(2e5\)的桶
- 若一个比答案小的值的桶为\(0\)了:答案更新为它
- 若这个\(mex\)的桶突然有值了:暴力枚举答案变大,第一个桶里没值的就是答案,更新。
有小伙伴会问,这复杂度不上天了?其实不然。移动\(ans\)的总复杂度(好像)是\(O(n\sqrt n)\)的,因为:
当区间长度增大时,\(ans\)的移动是均摊\(O(\text{区间长度})\)的(最坏情况(好像)是加进来的数就变成了一个递增序列)。
当区间减小时,\(ans\)是直接更新的。所以\(ans\)指针的移动和\(L,R\)指针的移动次数是同级的。
由于莫队中,区间减小增大不是交替的(不存在\(L\)动一次交替然后\(R\)动一次)(都是一个动完再动另外一个),所以最终复杂度\(O(n\sqrt 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\n",be[t]); return 0; }