您的位置:首页 > 其它

【清华集训2014】mex

2016-03-09 19:59 211 查看

Description

有一个长度为n的数组{a1,a2,…,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。

Solution

一眼看过去,很明显就是数据结构。

不过,用什么?怎么维护?

是个问题?

用什么

哎呀,发现很难找到一个可以在线的数据结构去维护。那么离线呢,好像离线可以。以下标线段树为节点的线段树,无法判重值,好像不能维护权值,想到不能维护权值,那么就有很多数据结构不能用了,维护权值的数据结构。

有什么数据结构是维护下标的吗,最显然的,函数式线段树。

怎么维护

函数式线段树在这题,很明显是维护下标的了。离线打法好!既然我们要用离线,如果是从左到右的,输入l[i],r[i](询问l[i]到r[i]的区间)那么就是以r[i]为关键字从小到大排序。那么我们在函数式线段树的加入中就锁定了r[i]了。

现在就很容易想了,比如说我现在要询问l到r中的答案,因为我们线段树的下标是权值,那么如果1到l的线段树中有一个下标是小于l的,那么答案就存在于这个区间(维护的是权值,越往左越小。下标小与l,那么肯定是l到r中没有的下标,而且肯定也没有这个值)。

那么很显然,我们维护的是在权值是l到r中出现过得最小下标。

Code

[code]#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
const int maxn=200007;
using namespace std;
int i,j,k,l,n,m,ber;
int a[maxn],ans[maxn];
struct nod{
    int a,b,c;
}b[maxn];
int t[maxn*3];
bool cmp(nod x,nod y){
    return x.b<y.b;
}
void insert(int x,int l,int r,int y,int z){
    if(l==r){
        t[x]=z;    
    }
    else{
        int mid=(l+r)/2;
        if(y<=mid)insert(x*2,l,mid,y,z);
        else insert(x*2+1,mid+1,r,y,z);
        t[x]=min(t[x*2],t[x*2+1]);
    }
}
int get(int x,int l,int r,int z){
    if(l==r) return l;
    int mid=(l+r)/2;
    if(t[x*2]<z) return get(x*2,l,mid,z);
    else return get(x*2+1,mid+1,r,z);
}
int main(){
    scanf("%d%d",&n,&m);
    fo(i,1,n){
        scanf("%d",&a[i]);
        if(a[i]>n+1)a[i]=n+1;
    }
    fo(i,1,m){
        scanf("%d%d",&b[i].a,&b[i].b);
        b[i].c=i;
    }
    sort(b+1,b+1+m,cmp);
    ber=1;
    fo(i,1,n){
        insert(1,0,n+1,a[i],i);
        fo(j,ber,m){
            if(b[j].b>i){
                ber=j;
                break;
            }
            ans[b[j].c]=get(1,0,n+1,b[j].a);
        }
    }
    fo(i,1,m) printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: