#莫队,分块#洛谷 4137 JZOJ 3547 mex

本文介绍了一种解决区间内最小未出现过自然数的算法,通过将大于数组长度的数转换并使用莫队算法进行离线查询,有效处理了大量数据的询问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

有一个长度为nnn的数组[a1,a2,...,an][a1,a2,...,an][a1,a2,...,an]mmm次询问,每次询问一个区间内最小没有出现过的自然数。


分析

其实这道题出的不算很好,因为即使a≤109a\leq 10^9a109,也只是纸老虎,因为一共才不超过2×1052\times 10^52×105个数,嗯,所以其实并没有什么用,只要把超过nnn的数都变成n+1n+1n+1就可以了,然后既然离线,就直接莫队就可以了 (我知道正解是主席树)


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#define rr register
using namespace std;
struct rec{int l,r,rk;}b[200001];
int n,m,bk,cnt[200011],a[200001],ans,answ[200001];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
bool cmp(rec x,rec y){
	if (x.l/bk!=y.l/bk) return x.l/bk<y.l/bk;
	return x.r<y.r; 
}
inline void del(int x){
	if (!(--cnt[a[x]])&&ans>a[x]) ans=a[x];
}
inline void add(int x){
	if ((++cnt[a[x]])==1){
		rr int tmp=a[x];
		if (ans==tmp)
		while (++tmp){
			if (!cnt[tmp]) {ans=tmp; return;}
		}
	}
}
signed main(){
	n=iut(); m=iut(); bk=pow(n,9.0/17);
	for (rr int i=1;i<=n;++i) a[i]=iut();
	for (rr int i=1;i<=n;++i) if (a[i]>n) a[i]=n+1;
	for (rr int i=1;i<=m;++i) b[i]=(rec){iut(),iut(),i};
	sort(b+1,b+1+m,cmp);
	rr int l=b[1].l,r=b[1].l-1;
	for (rr int i=1;i<=m;++i){
		while (l>b[i].l) add(--l);
		while (l<b[i].l) del(l++);
		while (r<b[i].r) add(++r);
		while (r>b[i].r) del(r--);
		answ[b[i].rk]=ans;
	}
	for (rr int i=1;i<=m;++i) printf("%d\n",answ[i]);
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值