zoukankan      html  css  js  c++  java
  • 【LuoguP4137】区间mex-主席树

    测试地址:区间mex
    做法:本题需要用到主席树。
    看到本题是离线的,很多同学想到了很显然的莫队做法,或者一些奇奇怪怪的离线做法,但实际上在线做法是有的:主席树。
    考虑转换条件,我们要求最小的在一个区间中没出现过的自然数,如果把原数列看做往一个空序列中一个一个插入元素,那实际上我们找的就是在某段时间内没有被插入过的最小的元素。考虑按照权值建线段树,对于每个线段树中的区间,我们存储这个区间中最久没有被插入过的点上一次被修改的时间,如果这个时间在所询问的左端点之前,那么就意味着在我们询问的区间里,存在一个在该范围中的元素没有出现过,那么我们就可以这样查找下去找到这个元素了。这个操作显然可以可持久化,于是建一棵主席树就好了。
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,m,len,tot=0,a[200010]={0},low=0,ans,p[200010];
    int rt[200010]={0},ch[4000010][2]={0},seg[4000010];
    struct forsort
    {
        int val,id;
    }f[200010];
    
    bool cmp(forsort a,forsort b)
    {
        return a.val<b.val;
    }
    
    void pushup(int no)
    {
        seg[no]=min(seg[ch[no][0]],seg[ch[no][1]]);
    }
    
    void build(int &v,int l,int r)
    {
        if (!v) v=++tot;
        if (l==r) {seg[v]=0;return;}
        int mid=(l+r)>>1;
        build(ch[v][0],l,mid);
        build(ch[v][1],mid+1,r);
        pushup(v);
    }
    
    void insert(int &v,int last,int l,int r,int x,int tim)
    {
        if (!v)
        {
            v=++tot;
            seg[v]=seg[last];
        }
        if (l==r) {seg[v]=tim;return;}
        int mid=(l+r)>>1;
        if (x<=mid) insert(ch[v][0],ch[last][0],l,mid,x,tim),ch[v][1]=ch[last][1];
        else insert(ch[v][1],ch[last][1],mid+1,r,x,tim),ch[v][0]=ch[last][0];
        pushup(v);
    }
    
    void query(int v,int l,int r,int limit)
    {
        if (seg[v]>=limit) return;
        if (l==r) {ans=l;return;}
        int mid=(l+r)>>1;
        if (!ans&&seg[ch[v][0]]<limit) query(ch[v][0],l,mid,limit);
        if (!ans&&seg[ch[v][1]]<limit) query(ch[v][1],mid+1,r,limit);
    }
    
    int main()
    {
        freopen("mex.in","r",stdin);
        freopen("mex.out","w",stdout);
    
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&f[i].val);
            f[i].id=i;
        }
    
        sort(f+1,f+n+1,cmp);
        len=0;
        f[0].val=-1;
        for(int i=1;i<=n;i++)
        {
            if (i==1||f[i].val!=f[i-1].val)
            {
                if (f[i].val>f[i-1].val+1) {low=f[i-1].val+1;break;}
                p[++len]=f[i].val;
            }
            a[f[i].id]=len;
        }
        if (!low) low=f[n].val+1;
    
        if (len)
        {
            build(rt[0],1,len);
            for(int i=1;i<=n;i++)
            {
                if (a[i]) insert(rt[i],rt[i-1],1,len,a[i],i);
                else rt[i]=rt[i-1];
            }
        }
    
        for(int i=1;i<=m;i++)
        {
            int L,R;
            scanf("%d%d",&L,&R);
            if (!len) printf("0
    ");
            else
            {
                ans=0;
                query(rt[R],1,len,L);
                if (!ans) printf("%d
    ",low);
                else printf("%d
    ",p[ans]);
            }
        }
    
        return 0;
    }
  • 相关阅读:
    Flex动画
    八大排序算法
    Android switch语句“case expressions must be constant expressions”
    MySQL修改root密码的多种方法
    Android中ListView控件onItemClick事件中获取listView传递的数据
    超详细Android接入支付宝支付实现,有图有真相
    Android蓝牙开发---与蓝牙模块进行通信
    Leecode no.19 删除链表的倒数第 N 个结点
    玩转java静态/动态代理
    Leecode no.198. 打家劫舍
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793496.html
Copyright © 2011-2022 走看看