1. 程式人生 > >分塊+莫隊||BZOJ3339||BZOJ3585||Luogu4137||Rmq Problem / mex

分塊+莫隊||BZOJ3339||BZOJ3585||Luogu4137||Rmq Problem / mex

題面:P4137 Rmq Problem / mex

題解:先莫隊排序一波,然後對權值進行分塊,找出第一個沒有填滿的塊,直接for一遍找答案。

除了bzoj3339以外,另外兩道題Ai範圍都是1e9。顯然最劣情況下答案是N,所以大於N的Ai都直接無視就可以。

由於求的是最小的自然數,自然數包括0,所以要額外處理一下含有0的塊。我這裡是直接把0拖出來放在第0塊了。

程式碼:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5
#include<cmath> 6 using namespace std; 7 inline int rd(){ 8 int f=1,x=0;char c=getchar(); 9 while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} 10 while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} 11 return f*x; 12 } 13 const int maxn=200005,maxm=200005,max_block=500; 14
int N,M,A[maxn],l,r,block,Ans[maxm],vis[maxn],cnt[max_block],num,belong[maxn]; 15 struct Q{ 16 int id,l,r; 17 }q[maxm]; 18 inline bool cmp(const Q&a,const Q&b){ 19 if(belong[a.l]==belong[b.l])return a.r<b.r; 20 return a.l<b.l; 21 } 22 inline void Add(int x){ 23 if(x<=N){
24 if(vis[x]==0)cnt[belong[x]]++; 25 vis[x]++; 26 } 27 return; 28 } 29 inline void Del(int x){ 30 if(x<=N){ 31 vis[x]--; 32 if(vis[x]==0)cnt[belong[x]]--; 33 } 34 return; 35 } 36 int main(){ 37 N=rd();M=rd(); 38 block=sqrt(N); 39 num=N/block; 40 if(N%block)num++; 41 for(int i=1;i<=N;i++){ 42 A[i]=rd(); 43 belong[i]=(i-1)/block+1; 44 } 45 belong[0]=0; 46 for(int i=1;i<=M;i++){ 47 q[i].id=i; 48 q[i].l=rd(); 49 q[i].r=rd(); 50 } 51 sort(q+1,q+M+1,cmp); 52 l=1;r=0; 53 for(int i=1;i<=M;i++){ 54 int ql=q[i].l,qr=q[i].r,id=q[i].id; 55 while(l<ql)Del(A[l++]); 56 while(l>ql)Add(A[--l]); 57 while(r<qr)Add(A[++r]); 58 while(r>qr)Del(A[r--]); 59 if(cnt[0]==0){ 60 Ans[id]=0; 61 continue; 62 } 63 int t=-1; 64 for(int j=1;j<=num;j++){ 65 if(j!=num&&cnt[j]!=block){ 66 t=j; 67 break; 68 } 69 else if(cnt[j]!=N-(num-1)*block) t=j; 70 } 71 if(t==-1){ 72 Ans[id]=N; 73 continue; 74 } 75 int f=(t-1)*block+1,toj=t*block; 76 for(int j=f;j<=toj;j++) 77 if(vis[j]==0){ 78 Ans[id]=j; 79 break; 80 } 81 } 82 for(int i=1;i<=M;i++)printf("%d\n",Ans[i]); 83 return 0; 84 }

 

By:AlenaNuna