您的位置:首页 > 其它

[BZOJ3585]mex

2017-09-24 15:13 253 查看
考场上觉得是用可持久化线段树,但是在存储方面卡了很久,最后直接写了个暴力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));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: