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";
}
}
时间会刺破青春表面的彩饰,会在美人的额上掘深沟浅槽;会吃掉稀世之珍!天生丽质,什么都逃不过他那横扫的镰刀。
博主写的那么好,就不打赏一下么(打赏在右边)