洛谷P4137 Rmq Problem / mex 基础莫队


洛谷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 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;
}
发布了109 篇原创文章 · 获赞 33 · 访问量 3550

猜你喜欢

转载自blog.csdn.net/weixin_42431507/article/details/98967014