BZOJ_3585_mex && BZOJ_3339_Rmq Problem_主席树
BZOJ_3585_mex && BZOJ_3339_Rmq Problem_主席树
Description
有一个长度为n的数组{a1,a2,...,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。
Input
第一行n,m。
第二行为n个数。
从第三行开始,每行一个询问l,r。
Output
一行一个数,表示每个询问的答案。
Sample Input
5 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5
Sample Output
1
2
3
0
3
2
3
0
3
HINT
数据规模和约定
对于100%的数据:
1<=n,m<=200000
0<=ai<=109
1<=l<=r<=n
对于30%的数据:
1<=n,m<=1000
分块链接http://www.cnblogs.com/suika/p/8890783.html
对每个前缀维护每个数最后出现的位置并维护出这个的最小值。
查询[L,R]时找到R对应的前缀,然后主席树上二分,用左边的最小值和L比较。
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 200050 inline char nc() { static char buf[100000],*p1,*p2; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int rd() { register int x=0; register char s=nc(); while(s<'0'||s>'9') s=nc(); while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc(); return x; } int t[N*25],ls[N*25],rs[N*25],n,m,a[N],cnt,root[N]; void insert(int x,int &y,int l,int r,int v,int w) { y=++cnt; if(l==r) { t[y]=w; return ; } int mid=(l+r)>>1; if(v<=mid) rs[y]=rs[x],insert(ls[x],ls[y],l,mid,v,w); else ls[y]=ls[x],insert(rs[x],rs[y],mid+1,r,v,w); t[y]=min(t[ls[y]],t[rs[y]]); } int query(int x,int l,int r,int v) { if(l==r) return l; int mid=(l+r)>>1; if(t[ls[x]]<v) return query(ls[x],l,mid,v); else return query(rs[x],mid+1,r,v); } int main() { n=rd(); m=rd(); int i,x,y; for(i=1;i<=n;i++) { a[i]=rd(); a[i]=min(a[i],n); insert(root[i-1],root[i],0,n,a[i],i); } for(i=1;i<=m;i++) { x=rd(); y=rd(); printf("%d\n",query(root[y],0,n,x)); } }