标签:线段树 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)); } }
标签:线段树 amp include 位置 如何 否则 scanf clu class
原文地址:http://www.cnblogs.com/jefflyy/p/7587277.html