洛谷P4137 Rmq Problem / mex
标签
- 基础莫队
前言
- 我的csdn和博客园是同步的,欢迎来访danzh-博客园~
- 很简单的莫队哦
简明题意
- 询问区间[L,R]中不存在的最小的数
思路
- 一看题,感觉莫队可以写。然后看看容不容易转移~
- 首先remove,假设当前区间最小的不存在的数是ans。那么很显然的是,当前区间中一定存在[0,ans)中的所有数,ans这个数肯定不存在,>ans的数全部都可能存在。所以现在remove操作只有两种情况,要么remove的是<ans的,要么remove的>ans。
- remove的>ans,显然并不会影响答案(因为>ans的数就算全没了,ans那个数仍然不存在,所以答案仍然是ans),所以不需要更新答案,只需要开一个数组cnt[]记录每个数出现的次数。
- remove的<ans。那么答案一定会更新吗?不一定的,判断一下remove的数出现的次数就能判断是否需要更新ans
- 然后讲一讲add操作。大家可以举例,会发现,只有当添加一个和ans相等的数,才会影响答案。
- 前面说过了,当前答案是ans时,当前区间一定存在[0,ans)中的所有数,所以你新加一个[1,ans)的数,并不影响答案。如果新加的数>ans,显然还是对答案没有影响,因为不管你怎么加数,ans那个数仍然不存在。现在唯一没有考虑的就是add一个==ans的数。
- 当add一个==ans,答案一定会变。因为加了后ans就存在了嘛。问题是,加了之后,答案是什么呢?首先答案一定是>ans的。那么这里我的做法是从ans+1开始遍历一遍,一旦发现有一个数的cnt ==0,那么他就是答案了
注意事项
- 无
- 这题看似应该离散化一下的(因为序列中的数的范围是1e9的,cnt数组就会炸掉),然而普通离散化会出问题,假如原数列是0,1,2,3,5,9999,233,4离散化后是0,1,2,3,5,7,6,4那么用离散化后的数跑一遍会发现[1,8]的答案是8,所以发现问题了吗?也就是普通离散化并没有维护原序列的连续性,而只维护了原序列的大小关系,所以导致错误。
- 所以这里我有一个做法,是将原本连续的数离散成仍然连续的数,原本不连续的数离散时中间隔一个数。比如0,1,2,3,5,9999,233,4离散成0,1,2,3,5,9,7,4,现在查询[1,8]答案应该是6,就是答案。这个做法我还没实践,但是看起来是可行的~然而洛谷数据并没有把a[i]给的很大,所以不李三花也能过
总结
- 做莫队最重要的就是转移了~
AC代码
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 2e5 + 10;
int pos[maxn];
struct Query
{
int l, r, id;
bool op