主席树||可持久化线段树+离散化 || 莫队+分块 ||BZOJ 3585: mex || Luogu P4137 Rmq Problem / mex
题解:
先离散化,然后插一堆空白,大体就是如果(对于以a.data<b.data排序后的A)A[i-1].data+1!=A[i].data,则插一个空白叫做A[i-1].data+1,
开头和最尾也要这么插,意义是如果取不了A[i-1]了,最早能取的是啥数。要把这些空白也离散化然后扔主席树里啊。
主席树维护每个数A[i]出现的最晚位置(tree[i].data),查询时查询root[R]的树中最早的data<L的节点(这意味着该节点的下标离散化前代
表的数没有在区间L到R中)。
顺带一提,这道题也可以用莫队套分块做,原理十分好理解,分块维护的是权值,块[i]维护该块是否被填满。我也扔了代码。
另外,我主席树的空间开的其实是不对的,但是bzoj空间比较卡,所以开小点理论上是不对的,但是数据没有那么极端而已。
代码:
主席树||可持久化线段树+离散化版:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define max(a,b) ((a)>(b)?(a):(b)) 6 #define min(a,b) ((a)<(b)?(a):(b)) 7 using namespace std; 8 inline int rd(){ 9 int x=0,f=1;char c=getchar(); 10 while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} 11 while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} 12 return f*x; 13 } 14 const int maxn=200000+50,maxm=200000+50,inf=1<<30; 15 int N,M,cor[maxn<<1],lsh_cnt=0,root[maxn<<1],num_treenode=0,L,R; 16 bool pb[maxn<<1]; 17 struct _A{int id,yn,data;}A[maxn]; 18 inline bool cmp(const _A&a,const _A&b){return a.yn<b.yn;} 19 struct Tree{ 20 int l,r,data,ls,rs; 21 }t[maxn*25]; 22 inline void Build(int x,int l,int r){ 23 t[x].l=l;t[x].r=r;int mid=(l+r)>>1; 24 if(l==r){ 25 if(pb[l])t[x].data=0; 26 return; 27 } 28 Build(t[x].ls=++num_treenode,l,mid); 29 Build(t[x].rs=++num_treenode,mid+1,r); 30 return; 31 } 32 inline void Update(int u,int x,int q,int s){ 33 int l=t[u].l,r=t[u].r,mid=(l+r)>>1,ls=t[u].ls,rs=t[u].rs; 34 t[x].l=l;t[x].r=r; 35 if(l==r&&l==q){t[x].data=s; return;} 36 if(q<=mid){t[x].rs=rs; Update(ls,t[x].ls=++num_treenode,q,s);} 37 else{t[x].ls=ls; Update(rs,t[x].rs=++num_treenode,q,s);} 38 ls=t[x].ls;rs=t[x].rs; 39 t[x].data=min(t[ls].data,t[rs].data); 40 return; 41 } 42 inline int Query(int x,int s){ 43 int l=t[x].l,r=t[x].r,ls=t[x].ls,rs=t[x].rs; 44 if(l==r)return l; 45 if(t[ls].data<s)return Query(ls,s);else return Query(rs,s); 46 } 47 inline bool cmp2(const _A&a,const _A&b){return a.id<b.id;} 48 int main(){ 49 N=rd();M=rd(); 50 for(int i=1;i<=N;i++){A[i].yn=rd();A[i].id=i;} 51 sort(A+1,A+N+1,cmp); 52 if(A[1].yn!=0){ 53 cor[++lsh_cnt]=0; 54 pb[lsh_cnt]=1; 55 } 56 A[1].data=++lsh_cnt; 57 cor[lsh_cnt]=A[1].yn; 58 for(int i=2;i<=N;i++) 59 if(A[i].yn!=A[i-1].yn){ 60 if(A[i].yn!=A[i-1].yn+1){ 61 cor[++lsh_cnt]=A[i-1].yn+1; 62 pb[lsh_cnt]=1; 63 } 64 A[i].data=++lsh_cnt; 65 cor[lsh_cnt]=A[i].yn; 66 } 67 else A[i].data=lsh_cnt; 68 cor[++lsh_cnt]=A[N].yn+1; 69 pb[lsh_cnt]=1; 70 Build(root[0]=++num_treenode,1,lsh_cnt); 71 sort(A+1,A+N+1,cmp2); 72 for(int i=1;i<=N;i++) 73 Update(root[i-1],root[i]=++num_treenode,A[i].data,A[i].id); 74 while(M--){ 75 L=rd();R=rd(); 76 printf("%d\n",cor[Query(root[R],L)]); 77 } 78 return 0; 79 }
莫队套分块版:
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