LibreOJ #6285

题目链接: #6285. 数列分块入门 9

题目大意

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及询问区间的最小众数。

solution

一看这道题就两眼发昏两眼一抹黑抓瞎

一看这道题就毫无思路,那我们怎么做呢

我们仔细观察众数, 我们再看看我们用分块能分不到 \(400\)

那我们就可以 \(n * \sqrt{n}\) 预处理出任意两块之间的众数了

那我们任意两块之间的众数处理完了, 这题就做的差不多了

就差散块的处理方法, 我们散块可以直接处理, 暴力查找散块中是否有最优众数

大约为 \(n * \sqrt{n} * 2\)

毕竟前有散块后也有散块

但是有一些细节问题需要处理, 我们在计算个数的时候,会开一个桶,那我们就要离散化,然后在进行预处理

还有我们在处理散块的时候要注意, 是不是只有一块,如果只有一块,我们就不要算重了

Code:

/**
*    Author: Alieme
*    Data: 2020.9.8
*    Problem: LibreOJ #6285
*    Time: O()
*/
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <vector>

#define ll long long
#define rr register

#define inf 1e9
#define MAXN 100010
#define MAXM 6000

using namespace std;

inline int read() {
	int s = 0, f = 0;
	char ch = getchar();
	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
	return f ? -s : s;
}

void print(int x) {
	if (x < 0) putchar('-'), x = -x;
	if (x > 9) print(x / 10);
	putchar(x % 10 + 48);
}

int n, len, tot;

int a[MAXN], id[MAXN], name[MAXN], c[MAXN];

int f[MAXM][MAXM];

map<int, int> b;

vector<int> v[MAXN];

bool vis[MAXN];

inline void init(int x) {
	int num = 0, maxx = 0;
	memset(c, 0, sizeof c);
	for (rr int i = (x - 1) * len + 1; i <= n; i++) {
		c[a[i]]++;
		if (c[a[i]] > num || (c[a[i]] == num && name[a[i]] < name[maxx])) num = c[a[i]], maxx = a[i];
		f[x][id[i]] = maxx;
	}
}

inline int get(int l, int r, int x) {return upper_bound(v[x].begin(), v[x].end(), r) - lower_bound(v[x].begin(), v[x].end(), l);}

inline int query(int l, int r) {
	int maxx = f[id[l] + 1][id[r] - 1], num = 0;
	memset(vis, 0, sizeof vis);
	num = get(l, r, maxx);
	vis[maxx] = 1;
	for (rr int i = l; i <= min(id[l] * len, r); i++) {
		if (vis[a[i]]) continue;
		vis[a[i]] = 1;
		int res = get(l, r, a[i]);
		if (res > num || (res == num && name[a[i]] < name[maxx])) num = res, maxx = a[i];
	}
	if (id[l] == id[r]) return name[maxx];
	for (rr int i = (id[r] - 1) * len + 1; i <= r; i++) {
		if (vis[a[i]]) continue;
		vis[a[i]] = 1;
		int res = get(l, r, a[i]);
		if (res > num || (res == num && name[a[i]] < name[maxx])) num = res, maxx = a[i];
	}
	return name[maxx];
}

signed main() {
	n = read();
	len = sqrt(n);
	for (rr int i = 1; i <= n; i++) {
		a[i] = read(), id[i] = (i - 1) / len + 1;
		if (b[a[i]] == 0) {
			b[a[i]] = ++tot;
			name[tot] = a[i];
		}
		a[i] = b[a[i]];
		v[a[i]].push_back(i);
	}
	for (rr int i = 1; i <= n / len + 1; i++) init(i);
	for (rr int i = 1; i <= n; i++) {
		int l = read(), r = read();
		cout << query(l, r) << "\n";
	}
}
posted @ 2020-09-09 21:05  Aliemo  阅读(118)  评论(0编辑  收藏  举报