[BZOJ3585]mex

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3585]mex相关的知识,希望对你有一定的参考价值。

考场上觉得是用可持久化线段树,但是在存储方面卡了很久,最后直接写了个暴力T_T

正确的姿势十分巧妙,建立可持久化权值线段树,第$i$棵线段树的叶节点$x$存储$x$在$A_{1\cdots i}$中出现的最后位置(如果没有出现,记为$0$)

那么当查询$mex(\{A_{l\cdots r}\})$时,我们只需要在第$r$棵线段树中找最小的数,使得它在$A_{1\cdots r}$中出现的最后位置比$l$小即可

如何找?

只需维护区间最小值,查询时若左区间的最小值小于$l$,则答案在左区间,否则在右区间

细节:因为是求$mex$所以权值线段树要开到$[0,200001]$

#include<stdio.h>
#define maxa 200001
int ch[4000000][2],Tmin[4000000],root[200010],tot;
int min(int a,int b){return a<b?a:b;}
void insert(int lrt,int&rrt,int pos,int v,int l,int r){
	if(rrt==0){
		tot++;
		rrt=tot;
	}
	if(l==r){
		Tmin[rrt]=v;
		return;
	}
	int mid=(l+r)>>1;
	if(pos<=mid){
		ch[rrt][1]=ch[lrt][1];
		insert(ch[lrt][0],ch[rrt][0],pos,v,l,mid);
	}else{
		ch[rrt][0]=ch[lrt][0];
		insert(ch[lrt][1],ch[rrt][1],pos,v,mid+1,r);
	}
	Tmin[rrt]=min(Tmin[ch[rrt][0]],Tmin[ch[rrt][1]]);
}
int query(int x,int v,int l,int r){
	if(l==r)return l;
	int mid=(l+r)>>1;
	if(Tmin[ch[x][0]]<v)return query(ch[x][0],v,l,mid);
	return query(ch[x][1],v,mid+1,r);
}
int main(){
	int n,m,i,l,r;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		scanf("%d",&l);
		insert(root[i-1],root[i],l,i,0,maxa);
	}
	while(m--){
		scanf("%d%d",&l,&r);
		printf("%d\n",query(root[r],l,0,maxa));
	}
}

以上是关于[BZOJ3585]mex的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3585: mex|莫队算法

[BZOJ3585][BZOJ3339]mex

bzoj 3585: mex

bzoj#3585. mex

bzoj3585 mex

BZOJ3585: mex