P4137 Rmq Problem / mex
题意
回滚莫队见这篇博客
需要注意一个细节,写在代码注释里了。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2*1e5+10;
const int maxt=500;
int n,m,t,block,nowl,nowr,nowans,lastans;
int a[maxn],L[maxt],R[maxt],pos[maxn],cnt[maxn],tmpcnt[maxn],ans[maxn];
struct Query{int l,r,id;}qr[maxn];
inline bool cmp(Query x,Query y){return pos[x.l]==pos[y.l]?x.r>y.r:pos[x.l]<pos[y.l];}
inline void add(int x)
{
if(a[x]>n+1)return;
cnt[a[x]]++;
}
inline void erase(int x)
{
if(a[x]>n+1)return;
cnt[a[x]]--;
if(!cnt[a[x]])nowans=min(nowans,a[x]);
}
int main()
{
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++)scanf("%d%d",&qr[i].l,&qr[i].r),qr[i].id=i;
t=sqrt(n);block=n/t;
if(n%t)block++;
for(int i=1;i<=block;i++)L[i]=(i-1)*t+1,R[i]=min(i*t,n);
for(int i=1;i<=n;i++)pos[i]=(i-1)/t+1;
nowl=1,nowr=n;
for(int i=1;i<=n;i++)if(a[i]<=n+1)cnt[a[i]]++;
while(cnt[nowans])nowans++;
int last=0;lastans=nowans;
sort(qr+1,qr+m+1,cmp);
for(int i=1;i<=m;i++)
{
if(pos[qr[i].l]==pos[qr[i].r])
{
int res=0;
for(int j=qr[i].l;j<=qr[i].r;j++)if(a[j]<=n+1)tmpcnt[a[j]]++;
while(tmpcnt[res])res++;
ans[qr[i].id]=res;
for(int j=qr[i].l;j<=qr[i].r;j++)if(a[j]<=n+1)tmpcnt[a[j]]--;
continue;
}
if(last!=pos[qr[i].l])
{
nowans=lastans;//这里把nowans赋成上次换块时候的答案。
while(nowr<n)add(++nowr);//这个可能消去nowans。
while(nowl<L[pos[qr[i].l]])erase(nowl++);
last=pos[qr[i].l];lastans=nowans;
}
while(nowr>qr[i].r)erase(nowr--);
int tmp=nowans,tmpl=nowl;
while(nowl<qr[i].l)erase(nowl++);
ans[qr[i].id]=nowans;
while(nowl>tmpl)add(--nowl);
nowans=tmp;
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}