码迷,mamicode.com
首页 > 其他好文 > 详细

[BZOJ3585]mex

时间:2017-09-24 16:13:20      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:线段树   amp   include   位置   如何   否则   scanf   clu   class   

考场上觉得是用可持久化线段树,但是在存储方面卡了很久,最后直接写了个暴力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

标签:线段树   amp   include   位置   如何   否则   scanf   clu   class   

原文地址:http://www.cnblogs.com/jefflyy/p/7587277.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!