【BZOJ3339】Rmq Problem

描述 Description

给定一个长度为 n 的数列 A,数列的第 i 个元素是 Ai (从 1 开始编号)。你需要回答 q 个询问, 每个询问的参数是一个二元组(l ,r) (l ≤ r ,表示查询 mex({Al , Al+1 , … , Ar}) 的值。

所谓 mex ,就是 SG 定理中那个函数,也就是“Minimum Exclusive” 的缩写。对一个非负整数组成的集合 S, mex(S) 的值等于最小的不属于集合 S 的非负整数。

输入格式 InputFormat

输入文件第一行包含 2 个空格隔开的正整数 n 和 q,代表序列 A 的长度和询问个数。
输入文件第二行包含 n 个空格隔开的非负整数,第 i 个数表示 Ai 的值。
接下来 q 行,每行包含 2 个空格隔开的正整数 l 和 r (1 ≤ l ≤ r ≤ n),表示一个查询的参数。

输出格式 OutputFormat

输出文件应当包含 q 行,每行一个正整数,表示输入文件中对应询问的答案。

样例输入 SampleInput

7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7

样例输出 SampleOutput

3
0
3
2
4

数据范围和注释 Hint

第 1 个询问: mex({0,2,l}) = 3.
第 2 个询问: mex({2,l}) = 0.
第 3 个询问: mex({0,2,l,0}) = 3.
第 4 个询问: mex({l,0,l,3}) = 2.
第 5 个询问: mex({2,l,0,l,3,2}) = 4.

来源 Source

这里是题目来源。


BZOJ 3339


代码 Code

线段树。预处理区间 [1,x] 的 mex。每次更新区间内的 mex 的值。询问排序之后离线做。

#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define inf 0x7fffffff
struct tnode
{
    int l,r,mex;
};
struct question
{
    int l,r,id;
}q[200001];
tnode tree[1000000];
int a[200001],tmex[200001],ans[200001],next[200001],c[200001];
bool b[200001];
int i,j,t,n,m,k,p,z,y,x,last;
void build(int k,int tl,int tr)
{
    int i,j,t,mid;
    tree[k].l=tl;tree[k].r=tr;tree[k].mex=inf;
    if (tl==tr)
    {
        tree[k].mex=tmex[tl];
        return ;
    }
    mid=(tl+tr)>>1;
    build(k<<1,tl,mid);
    build(k<<1|1,mid+1,tr);
}
bool comp(question a,question b)
{
    if (a.l!=b.l) return (a.l<b.l);
    else if (a.r!=b.r) return a.r<b.r;
    else return a.id<b.id;
}
void change(int s)
{
    int i,j,t,end;
    t=a[s];
    tmex[s]=0;
    end=next[s];
    if (end==0) end=n;
    for (i=end;i>s;i--) 
    {
        if (tmex[i]>t) tmex[i]=t;
        else break;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++) scanf("%d",&a[i]);
    memset(b,false,sizeof(b));
    for (i=1;i<=n;i++)
    {
        if (b[a[i]]) next[c[a[i]]]=i-1;
        else next[c[a[i]]]=n;
        c[a[i]]=i;
        b[a[i]]=true;
    }
    t=0;
    memset(b,false,sizeof(b));
    for (i=1;i<=n;i++)
    {
        b[a[i]]=true;
        while (a[i]==t || b[t]) t++;
        tmex[i]=t;
    }
    build(1,1,n);
    for (i=1;i<=m;i++)
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+m+1,comp);
    last=1;
    for (i=1;i<=m;i++)
    {
        if (q[i].l==last)
        {
            ans[q[i].id]=tmex[q[i].r];
        }
        else
        {
            for (j=last;j<q[i].l;j++) change(j);
            ans[q[i].id]=tmex[q[i].r];
        }
        last=q[i].l;
    }
    for (i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}