洛谷P4137 Rmq Problem / mex 基础莫队
洛谷P4137 Rmq Problem / mex
标签
- 基础莫队
前言
- 很简单的莫队哦
简明题意
- 询问区间[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 operator < (const Query& a)const
{
if (pos[l] == pos[a.l])
return r < a.r;
return pos[l] < pos[a.l];
}
}; Query query[maxn];
int n, q, a[maxn], b[maxn], rec[maxn];
int ans = 0, cnt[maxn];
void add(int id)
{
if (cnt[a[id]]++ == 0 && a[id] == ans)
{
for (int i = ans + 1; ; i++)
if (cnt[i] == 0)
{
ans = i;
break;
}
}
}
void remove(int id)
{
if (cnt[a[id]]-- == 1 && a[id] < ans)
ans = a[id];
}
int ans0[maxn];
vector<int> ls;
void solve()
{
scanf("%d%d", &n, &q);
int len = sqrt(n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]), ls.push_back(a[i]), pos[i] = (i - 1) / len + 1;
for (int i = 1; i <= q; i++)
scanf("%d%d", &query[i].l, &query[i].r), query[i].id = i;
sort(query + 1, query + 1 + n);
//sort(ls.begin(), ls.end()),;
//int ls_len = unique(ls.begin(), ls.end()) - ls.begin();
/*int max_val = 0;
for (int i = 1; i <= n; i++)
max_val = max(max_val, a[i]);
rec[ls_len + 1] = max_val + 1;*/
//离散化
//for (int i = 1; i <= n; i++)
//{
// b[i] = lower_bound(ls.begin(), ls.begin() + ls_len, a[i]) - ls.begin() + 1;
// rec[b[i]] = a[i];//rec将离散化后的值映射回原来的值
//}
int l = 1, r = 0;
for (int i = 1; i <= q; i++)
{
int L = query[i].l, R = query[i].r;
while (l < L) remove(l++);
while (l > L) add(--l);
while (r < R) add(++r);
while (r > R) remove(r--);
ans0[query[i].id] = ans;
}
for (int i = 1; i <= q; i++)
printf("%d\n", ans0[i]);
}
int main()
{
// freopen("Testin.txt", "r", stdin);
solve();
return 0;
}
作者:danzh
QQ:1244536605
CSDN(和博客园同步):https://blog.csdn.net/weixin_42431507
-----------------------------------------------------------------------------------------------
朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其
它人怎么样,我们也能够保持自己的本色走下去。
—clj