bzoj3585 mex

3585: mex

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 1445  Solved: 725
[Submit][Status][Discuss]

Description

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

Input

  第一行n,m。
  第二行为n个数。
  从第三行开始,每行一个询问l,r。

Output

  一行一个数,表示每个询问的答案。

Sample Input

5 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5

Sample Output

1
2
3
0
3

HINT

数据规模和约定

  对于100%的数据:

  1<=n,m<=200000

  0<=ai<=109

  1<=l<=r<=n

分析:和spoj DQUERY以及bzoj2653类似.都是主席树的妙用.

   因为要求mex,每棵主席树内部维护的肯定是权值,维护权值的什么呢? 对于一个区间[l,r], 假设已经固定了右端点r,那么只需要保证左端点即可.当主席树处理到权值区间[x,y]时,如果[x,mid]都在l右边,那么mex肯定只会出现在[mid+1,y]中,否则就会出现在[x,mid]中. 那么第i棵主席树维护的就是下标区间[1,i]中权值的最左位置. 像线段树一样处理.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 200010;
int n,m,root[maxn],tot;

struct node
{
    int left,right,minn;
}e[maxn * 40];

void build(int &o,int l,int r)
{
    o = ++tot;
    e[o].minn = 0;
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    build(e[o].left,l,mid);
    build(e[o].right,mid + 1,r);
}

void pushup(int o)
{
    int temp = 0x7fffffff;
    if (e[o].left)
        temp = min(e[e[o].left].minn,temp);
    if (e[o].right)
        temp = min(e[e[o].right].minn,temp);
    e[o].minn = temp;
}

void update(int l,int r,int x,int &y,int pos,int v)
{
    e[y = ++tot] = e[x];
    if (l == r)
    {
        e[y].minn = v;
        return;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid)
        update(l,mid,e[x].left,e[y].left,pos,v);
    else
        update(mid + 1,r,e[x].right,e[y].right,pos,v);
    pushup(y);
}

int query(int l,int r,int x,int y)
{
    if (l == r)
        return l;
    int mid = (l + r) >> 1;
    if (e[e[y].left].minn >= x)
        return query(mid + 1,r,x,e[y].right);
    else
        return query(l,mid,x,e[y].left);
}

int main()
{
    scanf("%d%d",&n,&m);
    build(root[0],0,n);
    for (int i = 1; i <= n; i++)
    {
        int x;
        scanf("%d",&x);
        if (x >= n)
            x = n;
        update(0,n,root[i - 1],root[i],x,i);
    }
    for (int i = 1; i <= m; i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%d\n",query(0,n,l,root[r]));
    }

    return 0;
}

 

 

posted @ 2018-04-05 11:41 zbtrs 阅读(...) 评论(...) 编辑 收藏