P4137 Rmq Problem / mex

题目描述

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

输入输出格式

输入格式:

第一行n,m。

第二行为n个数。

从第三行开始,每行一个询问l,r。

输出格式:

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

输入输出样例

输入样例#1: 
5 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5
输出样例#1: 
1
2
3
0
3

说明

对于30%的数据:1<=n,m<=1000

对于100%的数据:1<=n,m<=200000,0<=ai<=10^9,1<=l<=r<=n

Solution:

  本题又是区间上的操作,而且操作还这么诡异,于是果断往莫队上想。

  很容易想到维护一段区间$[l,r]$的最小值$ansmin$,用一个数组统计每个数字出现的次数,然后每次对$ansmin$的值进行修改,具体就是当某数字增加时暴力求出当前最小的没有出现的数,当某数字减少时若减小到$0$则与$ansmin$取最小值就行了。

  但是有个很大的问题,本题的数据$a[i] leq 10^9$这就是真的骚,果断切掉这算法,看波题解,发现别人竟然用这方法$AC$了,真的神奇。于是忽略数据范围来乱写,果真$AC$了。

  最蛇皮的是,我想试一下模数取$520$能不能过,结果$10$分,神奇的是我换回原来代码后,死活$AC$不了,什么$RE,TLE,WA$都出来了,简直神奇。

  后面想到一个问题就是答案肯定最大为$200001$以内,因为一共就$200000$个数,每个被覆盖,最大显然是$200001$。

  于是就可以直接将比$200000$大的数去掉就OK了。整个复杂度是玄学的,嘿嘿!(巨说正解的mex求法就是分块,可以去学学)

  看了一下别人的算法,都是什么高超的数据结构(挖个坑下次学学用权值线段树+离线或者持久化写写这题),但还是贴一下莫队的代码吧,本题真蛇皮啊~~手动滑稽~~。

代码:

#include<bits/stdc++.h>
#define il inline
#define ll long long
using namespace std;
const int N=200005;
int n,m,ansmin,pos[N],a[N],ans[N],s[N];
struct data{
    int l,r,id;
}t[N];
il int gi()
{
    int a=0;char x=getchar();bool f=0;
    while((x<'0'||x>'9')&&x!='-')x=getchar();
    if(x=='-')x=getchar(),f=1;
    while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
    return f?-a:a;
}
il bool cmp(data a,data b){return pos[a.l]==pos[b.l]?a.r<b.r:a.l<b.l;}
il void change(int k,int u)
{
    if(a[k]>200000)return;
    if(u==1){
        s[a[k]]++;int i=ansmin;while(s[i])i++;ansmin=i;
    }
    else {
        s[a[k]]--;if(!s[a[k]])ansmin=min(ansmin,a[k]);
    }
}
int main()
{
    n=gi(),m=gi();
    int ss=int(sqrt(n));
    for(int i=1;i<=n;i++)a[i]=gi(),pos[i]=(i-1)/ss+1;
    for(int i=1;i<=m;i++)t[i].l=gi(),t[i].r=gi(),t[i].id=i;
    sort(t+1,t+m+1,cmp);
    for(int i=1,l=1,r=0;i<=m;i++){
        while(r<t[i].r)change(r+1,1),r++;
        while(r>t[i].r)change(r,-1),r--;
        while(l<t[i].l)change(l,-1),l++;
        while(l>t[i].l)change(l-1,1),l--;
        if(t[i].l==t[i].r){ans[t[i].id]=0;continue;}
        ans[t[i].id]=ansmin;
    }
    for(int i=1;i<=m;i++)printf("%d
",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/five20/p/8798672.html