码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 3585: mex

时间:2017-05-27 19:18:00      阅读:137      评论:0      收藏:0      [点我收藏+]

标签:stdin   stat   min   open   答案   names   个数   using   for   

3585: mex

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 969  Solved: 511
[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


  对于30%的数据:


  1<=n,m<=1000

以权值为下标,

minn[i]=j,表示i所代表的权值为[l,r]的区间,最早出现的位置为j

例:0 2 1 0 1 3 2

对于root[7]来说,

[0,3]=1, 0最早出现在第1个位置

[1,3]=2, 2最早出现在第2个位置

查询[l,r]时,在root[r]里查询

如果左子区间的minn>=l,说明权值小的左边一半都最早出现在l以后,就往右孩子找

否则,说明权值小的左边一半有没有出现在l之后的,就往左孩子找

因为是在root[r]里,所以保证不超过右边界

对于10^9的权值,离散化?

不。

如果权值>n,直接让它=n

因为此时<n中一定有没有出现的数

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200001
using namespace std;
int n,q,tot;
int root[N],minn[N*20];

    int lc[N*20],rc[N*20];
    void change(int &now,int pre,int l,int r,int pos,int val)
    {
        if(!now) now=++tot;
        if(l==r) 
        {
            minn[now]=val;
            return;
        }
        int mid=l+r>>1;
        if(pos<=mid) 
        {
            change(lc[now],lc[pre],l,mid,pos,val);
            rc[now]=rc[pre];
        }
        else 
        {
            change(rc[now],rc[pre],mid+1,r,pos,val);
            lc[now]=lc[pre];
        }
        minn[now]=min(minn[lc[now]],minn[rc[now]]);
    }
    int query(int now,int l,int r,int pos)
    {
        if(l==r) return l;
        int mid=l+r>>1;
        if(minn[lc[now]]>=pos) return query(rc[now],mid+1,r,pos);
        return query(lc[now],l,mid,pos);
    }

int main()
{
    freopen("mex.in","r",stdin);
    freopen("mex.out","w",stdout);
    int m;
    scanf("%d%d",&n,&m);
    int x;
    for(int i=1;i<=n;i++) 
    {
        scanf("%d",&x);
        if(x>n) x=n;
        change(root[i],root[i-1],0,n,x,i);
    } 
    int l,r;
    while(m--)
    {
        scanf("%d%d",&l,&r);
        printf("%d\n",query(root[r],0,n,l));
    }
}

 

 

bzoj 3585: mex

标签:stdin   stat   min   open   答案   names   个数   using   for   

原文地址:http://www.cnblogs.com/TheRoadToTheGold/p/6914035.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!