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

Sample Output

1
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));
    }
}

 

posted @ 2018-05-20 07:31  fcwww  阅读(360)  评论(0编辑  收藏  举报