其他分享
首页 > 其他分享> > [Ynoi2019 模拟赛] Yuno loves sqrt technology III

[Ynoi2019 模拟赛] Yuno loves sqrt technology III

作者:互联网

题面

Yuno loves sqrt technology III

题解

一道很水的黑题。
做过蒲公英的同学应该都知道这和蒲公英很类似。
不同的是它维护的是区间众数的个数。
因为区间众数不具有可加性,再加上强制在线,显然是用分块来维护。
首先正常分块。
预处理块内信息时的整合就直接 \(\sqrt(n) ^ 3\) 暴力枚举,得到块 \(l\) 到 块 \(r\) 的区间众数个数。
对于询问就和正常分块相同,暴力处理两边零散的情况。
但不同于蒲公英的是,这道题数据范围更大些,再加一个 \(logn\) 的二分查找,显然是不行的。
所以我们需要找到一个更快的处理方法。
记录 \(a[i]\) 在数值 \(a[i]\) 中的次序 \(it\), 以及每个 \(a[i]\) 出现的位置。
首先用 \(ans\) 记录整块区间的信息。
对于左边零散的部分:
如果 \(it + ans - 1 < a[i]的总个数\),那么显然 \(a[i]\) 是有可能更新答案的,那么我们再看 \(it + ans - 1\) 这个次序的 \(a[i]\) 出现的位置是否在我们询问的边界 \(r\) 内,如果是,就说明 \(a[i]\) 在 \(r\) 内是至少有 \(ans + 1\) 个答案的。所以我们就直接更新答案就是了。
对于右边零散的部分同理,只需要判断位置是否在左边界内就行了,具体细节请看码。

代码

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>

using namespace std;

const int N = 5e5 + 10, M = 710;

int n, m, a[N], b[N], len = 0, tot[N], block, L[M], R[M], Max[M][M], ans = 0, bel[N], cnt[N];

vector < int > pos[N];

inline int query(int l, int r) {
	int p = bel[l], q = bel[r], ans = 0;
	if(p == q) {
		for(int i = l; i <= r; i++) tot[a[i]] = 0;
		for(int i = l; i <= r; i++)
			ans = max(ans, ++tot[a[i]]);
	}
	else {
		ans = Max[p + 1][q - 1];
		for(int i = l; i <= R[p]; i++) {
			int it = cnt[i]; while(it + ans < pos[a[i]].size() && pos[a[i]][it + ans] <= r) ++ans;
		}
		for(int i = L[q]; i <= r; i++) {
			int it = cnt[i]; while(it - ans >= 0 && pos[a[i]][it - ans] >= l) ++ans;
		}
	}
	return ans;
}

inline void read(int &x) {
	x = 0; int f = 1, c = getchar();
	for(; !isdigit(c); c = getchar())
		if(c == '-')
			f = -1;
	for(; isdigit(c); c = getchar())
		x = x * 10 + c - 48;
	x *= f;
}

int main() {
	read(n), read(m);
	for(int i = 1; i <= n; i++) read(a[i]), b[i] = a[i];
	sort(b + 1, b + 1 + n);
	len = unique(b + 1, b + 1 + n) - b - 1;
	for(int i = 1; i <= n; i++)
		a[i] = lower_bound(b + 1, b + 1 + n, a[i]) - b,
		pos[a[i]].push_back(i), cnt[i] = pos[a[i]].size() - 1;
	block = sqrt(n);
	for(int i = 1; i <= block; i++)
		L[i] = (i - 1) * block + 1,
		R[i] = i * block;
	if(R[block] < n) block++, L[block] = R[block - 1] + 1, R[block] = n;
	for(int i = 1; i <= block; i++)
		for(int j = L[i]; j <= R[i]; j++)
			bel[j] = i;
	for(int l = 1; l <= block; l++) {
		memset(tot, 0, sizeof tot);
		for(int r = l; r <= block; r++) {
			Max[l][r] = Max[l][r - 1];
			for(int j = L[r]; j <= R[r]; j++)
				Max[l][r] = max(Max[l][r], ++tot[a[j]]);
		}
	}
	for(int i = 1, l, r; i <= m; i++) {
		read(l), read(r);
		l ^= ans, r ^= ans;
		if(l > r) swap(l, r);
		printf("%d\n", ans = query(l, r));
	}
	return 0;
}

标签:Ynoi2019,bel,int,sqrt,read,ans,include,III,getchar
来源: https://www.cnblogs.com/sjzyh/p/15027769.html