zoukankan      html  css  js  c++  java
  • BZOJ3585: mex(主席树)

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 1413  Solved: 713
    [Submit][Status][Discuss]

    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

    Source

    By 佚名提供

    考场上写的cc_hash_table+莫队,成功水到70分233

    正解是权值线段树

    让线段树中下标为$i$的位置表示权值为$i$的数最后一次出现的位置

    同时维护一下区间最小值

    再可持久化一下

    询问的时候直接在第$r$棵树中找到一个最小的位置,满足这个下标出现的位置$<=l$

    #include<cstdio>
    #include<algorithm>
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
    char buf[1<<20],*p1=buf,*p2=buf;
    using namespace std;
    const int MAXN=4*1e6+10,INF=1e9+10;
    inline int read()
    {
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    struct node
    {
        int mn,ls,rs;
    }T[MAXN];
    int root[MAXN],tot=0;
    void update(int k){T[k].mn=min(T[T[k].ls].mn,T[T[k].rs].mn);}
    void Insert(int &k,int pre,int l,int r,int pos,int val)
    {
        if(!k) k=++tot;
        if(l==r){T[k].mn=val;return ;}
        int mid=l+r>>1;
        if(pos<=mid) T[k].rs=T[pre].rs,Insert(T[k].ls,T[pre].ls,l,mid,pos,val);
        else         T[k].ls=T[pre].ls,Insert(T[k].rs,T[pre].rs,mid+1,r,pos,val);
        update(k);
    }
    int Query(int k,int l,int r,int val)
    {
        if(l==r) return l;
        int mid=l+r>>1;
        if(T[T[k].ls].mn<val) return Query(T[k].ls,l,mid,val);
        else                      return Query(T[k].rs,mid+1,r,val);
    }
    int main()
    {
        freopen("a.in","r",stdin);
        int N=read(),M=read();
        for(int i=1;i<=N;i++)
        {
            int val=read();
            Insert(root[i],root[i-1],0,N,val>N?N:val,i);
        }
        for(int i=1;i<=M;i++)
        {
            int l=read(),r=read();
            printf("%d
    ",Query(root[r],0,N,l));
        }
        return 0;
    }
  • 相关阅读:
    最近邻插值
    tp类型自动转换和自动完成
    tp读取器和写入器
    tp模型和数据库操作方法
    tp数据库操作
    tp请求和响应
    tp配置+路由+基本操作
    git的常见操作方法
    php 检查该数组有重复值
    公众号的TOKEN配置PHP代码
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/8665162.html
Copyright © 2011-2022 走看看