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


可以主席树上二分在线查询,也可以主席树离线,当然我肯定选择莫队啦!!!


这种具有区间可加性,而且相邻区间可以O(1) ,修改,故莫队可行。

对于莫队的del,删除元素,我们删除这个元素之后,直接与当前答案取个最小值即可。

对于莫队的add,添加元素,我们添加这个元素之后,判断与当前答案是否相等,若相等就让当前答案一直增加,直到不存在这个元素。

这题不用离散化,因为最多n个元素,所以答案不会大于n,故不会到达1e9


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=2e5+10;
int n,m,a[N],vis[N],res[N],mi,bl,cl,cr;
struct node{
	int l,r,id;
}t[N];
int cmp(const node &s1,const node &s2){
	return (s1.l/bl==s2.l/bl)?(s1.r<s2.r):(s1.l<s2.l);
}
inline void del(int x){
	if(!(--vis[a[x]]))	mi=min(mi,a[x]);
}
inline void add(int x){
	if((++vis[a[x]])==1){
		int t=a[x];
		if(t==mi){
			while(++t){
				if(!vis[t]){
					mi=t;	return;
				}
			}
		}
	}
}
signed main(){
	scanf("%d %d",&n,&m);	bl=sqrt(n);
	for(int i=1;i<=n;i++)	scanf("%d",&a[i]);
	for(int i=1;i<=m;i++)	scanf("%d %d",&t[i].l,&t[i].r),t[i].id=i;
	sort(t+1,t+1+m,cmp);	cl=1;
	for(int i=1;i<=m;i++){
		int L=t[i].l;	int R=t[i].r;
		while(cl<L)	del(cl++);
		while(cl>L)	add(--cl);
		while(cr<R)	add(++cr);
		while(cr>R)	del(cr--);
		res[t[i].id]=mi;
	}
	for(int i=1;i<=m;i++)	printf("%d\n",res[i]);
	return 0;
}
全部评论

相关推荐

零offer🐭🐭:联合国宣传大使
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务