[BZOJ3585][清华集训2014]mex 主席树

考虑用主席树维护到第i个位置时,每个数最后一次出现位置,也就是说维护的是n棵权值线段树,线段树上每个节点表示值域在此之内的每个数最后一次出现位置的最小值。
那么一个询问(l,r)就是在第r棵线段树上查最小的且上一次出现位置小于l的数,经典操作。
注意离散化的时候要把每个值和它+1扔进去离散化,而且要去重,因为不能破坏整数的连续性。
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200010;
int a[maxn],z[maxn<<1],n,m;
struct tree;
tree *NUL;
struct tree
{
    int mi;
    tree *so[2];
    tree(){mi=0;so[0]=so[1]=NUL;}
    void update(){mi=min(so[0]->mi,so[1]->mi);}
    void build(tree *lst,int p,int l,int r)
    {
        if(l==r) {mi=p;return;}
        int mid=(l+r)>>1;bool b=(a[p]>mid);
        int lx=b?mid+1:l,rx=b?r:mid;
        so[b^1]=lst->so[b^1];
        (so[b]=new tree)->build(lst->so[b],p,lx,rx);
        update();
    }
    int query(int p,int l,int r)
    {
        if(l==r||this==NUL) return l;
        int mid=(l+r)>>1;
        if(so[0]->mi<p) so[0]->query(p,l,mid);
        else so[1]->query(p,mid+1,r);
    }
}*rt[maxn];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        z[2*i-1]=a[i];z[2*i]=a[i]+1;
    }
    sort(z+1,z+2*n+1);
    int sz;
    sz=unique(z+1,z+2*n+1)-z-1;
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(z+1,z+sz+1,a[i])-z;
    NUL=new tree;NUL->so[0]=NUL->so[1]=NUL;
    rt[0]=new tree;
    for(int i=1;i<=n;i++)
        (rt[i]=new tree)->build(rt[i-1],i,1,sz);
    while(m--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%d\n",z[rt[r]->query(l,1,sz)]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值