[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]$
正确的姿势十分巧妙,建立可持久化权值线段树,第$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)); } }
相关文章推荐
- [BZOJ 3585]mex
- BZOJ 3585: mex|莫队算法
- BZOJ_3585_mex && BZOJ_3339_Rmq Problem_莫队+分块
- [BZOJ3585]mex
- BZOJ 3585: mex [主席树]
- bzoj 3585: mex
- 【BZOJ3585】mex
- [BZOJ3585]mex(离线+离散化+线段树)
- BZOJ 3585 mex - 莫队+(分块/树状数组+二分/乱搞/主席树)
- bzoj 3585: mex
- bzoj3585 mex
- 【BZOJ3585】mex
- [bzoj3339]Rmq Problem||[bzoj3585]mex_线段树
- [bzoj 3339&bzoj 3585]Rmq Problem&mex
- [BZOJ3585]mex 主席树
- BZOJ_3585_mex && BZOJ_3339_Rmq Problem_主席树
- [bzoj3585]mex
- 【BZOJ3585】mex【离线】【线段树】【mex】【离散化】
- bzoj 3585 mex - 线段树 - 分块 - 莫队算法
- BZOJ 3585 mex 莫队算法+分块