• 洛谷 P4137 Rmq Problem /mex 解题报告


    P4137 Rmq Problem /mex

    题意

    给一个长为(n(le 10^5))的数列({a}),有(m(le 10^5))个询问,每次询问区间的(mex)


    可以莫队然后对值域分块,这样求(mex)的复杂度就正确了

    一种更优的做法是按值域建可持久化线段树,对每个节点维护当前值域区间的最小出现位置,然后查询的时候就从(r)的那棵树一直尽量往左边走就好了


    Code:

    #include <cstdio>
    #include <cstring>
    const int N=2e5+10;
    #define ls ch[now][0]
    #define rs ch[now][1]
    #define ols ch[las][0]
    #define ors ch[las][1]
    int mi[N*30],ch[N*30][2],root[N],n,m,tot;
    int min(int x,int y){return x<y?x:y;}
    void rebuild(int las,int &now,int l,int r,int p,int d)
    {
        now=++tot;
        if(l==r){mi[now]=d;return;}
        int mid=l+r>>1;
        if(p<=mid) rebuild(ols,ls,l,mid,p,d),rs=ors;
        else ls=ols,rebuild(ors,rs,mid+1,r,p,d);
        mi[now]=min(mi[ls],mi[rs]);
    }
    int query(int now,int l,int r,int lim)
    {
        if(l==r) return l;
        int mid=l+r>>1;
        if(mi[ls]<lim) return query(ls,l,mid,lim);
        else return query(rs,mid+1,r,lim);
    }
    void build(int &now,int l,int r)
    {
        mi[now=++tot]=0;
        if(l==r) return;
        int mid=l+r>>1;
        build(ls,l,mid),build(rs,mid+1,r);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        memset(mi,0x3f,sizeof mi);
        build(root[0],1,++n);
        for(int a,i=1;i<n;i++)
        {
            scanf("%d",&a);
            if(a<n) rebuild(root[i-1],root[i],1,n,a+1,i);
            else root[i]=root[i-1];
        }
        for(int l,r,i=1;i<=m;i++)
        {
            scanf("%d%d",&l,&r);
            printf("%d
    ",query(root[r],1,n,l)-1);
        }
        return 0;
    }
    

    2019.1.28

  • 相关阅读:
    K3CLOUD表关联
    QLIKVIEW基础设置及初步了解
    CLOUD信用管理设置
    QLIKVIEW添加数据库连接
    MRP没生成MRP汇总表
    金蝶学习网站
    CLOUD常用设置
    BZOJ 3551: [ONTAK2010]Peaks加强版 Kruskal重构树+dfs序+主席树+倍增
    BZOJ 3732: Network Kruskal 重构树
    LOJ #2718. 「NOI2018」归程 Dijkstra+可持久化并查集
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10331887.html
Copyright © 2020-2023  润新知