3585: mex
Time Limit: 20 Sec Memory Limit: 128 MBDescription
有一个长度为n的数组{a1,a2,...,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。
Input
第一行n,m。
第二行为n个数。
从第三行开始,每行一个询问l,r。
Output
一行一个数,表示每个询问的答案。
Sample Input
5 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5
Sample Output
1
2
3
0
3
2
3
0
3
HINT
数据规模和约定
对于100%的数据:
1<=n,m<=200000
0<=ai<=109
1<=l<=r<=n
对于30%的数据:
1<=n,m<=1000
分析:莫队+权值分块;转移用莫队,查找分块sqrt(n)查;
没有啥思维难度,大力码就行了。
代码:
#include <bits/stdc++.h> const int maxn=2e5+10; int n,m,k,t,tot,sz,sz1,a[maxn],d[maxn],bl[maxn],bs[maxn],cnta[maxn],cntb[maxn],num[maxn],ans[maxn]; using namespace std; struct node { int l,r,id; bool operator<(const node&p)const { return bl[l]==bl[p.l]?r<p.r:bl[l]<bl[p.l]; } }qu[maxn]; int main() { int i,j; scanf("%d%d",&n,&m); for(i=1;i<=n;i++)scanf("%d",&a[i]),d[++tot]=a[i]; sort(d+1,d+tot+1); tot=unique(d+1,d+tot+1)-d-1; for(i=1;i<=n;i++)a[i]=lower_bound(d+1,d+tot+1,a[i])-d-1; if(d[1]!=0)tot=2; else { bool flag=false; for(i=2;i<=tot;i++)if(d[i]!=d[i-1]+1) { tot=d[i-1]+3; flag=true; break; } if(!flag)tot=tot+3; } for(i=1;i<=n;i++)if(d[a[i]+1]>tot-2) { a[i]=tot-1; } for(i=1;i<=m;i++) { int l,r; scanf("%d%d",&l,&r); qu[i]=node{l,r,i}; } sz=round(sqrt(n)+0.5); for(i=1;i<=n;i++)bl[i]=(i-1)/sz+1; sz1=round(sqrt(tot)+0.5); for(i=0;i<=tot-1;i++)bs[i]=i/sz1+1,num[bs[i]]++; sort(qu+1,qu+m+1); int l=1,r=0; for(i=1;i<=m;i++) { while(r<qu[i].r) { ++r; cnta[bs[a[r]]]+=(!cntb[a[r]]); ++cntb[a[r]]; } while(l>qu[i].l) { --l; cnta[bs[a[l]]]+=(!cntb[a[l]]); ++cntb[a[l]]; } while(l<qu[i].l) { --cntb[a[l]]; cnta[bs[a[l]]]-=(!cntb[a[l]]); l++; } while(r>qu[i].r) { --cntb[a[r]]; cnta[bs[a[r]]]-=(!cntb[a[r]]); r--; } for(j=1;;j++) { if(cnta[j]==num[j])continue; for(k=(j-1)*sz1;;k++) { if(cntb[k]==0)break; } break; } ans[qu[i].id]=k; } for(i=1;i<=m;i++)printf("%d ",ans[i]); return 0; } /* 3 6 1 2 3 1 1 2 2 3 3 1 2 2 3 1 3 */