bzoj4241 历史研究 分块
题目传送门
https://lydsy.com/JudgeOnline/problem.php?id=4241
题解
这道题要求出来的就是一个区间带权众数。
回忆一下一般的区间众数怎么求:
分块,对于每一次询问 \(l, r\),如果 \(l, r\) 不在同一个整块中,那么答案一定是中间的整块的众数,或者两旁的剩下来的数。
这个东西可以预处理一个 \(f[i][j]\) 表示从第 \(i\) 块到 \(j\) 的众数就可以单次 \(\sqrt n\) 求出了。
对于两旁的剩数,每个数可以预处理每个值的出现位置的序列,在上面二分求出每个数的出现次数。
可以发现上面的结论依然可以用于带权众数。
不过这道题的数据范围大了一点,有 \(10^5\),所以需要 \(O(1)\) 求出一个数在某一整段中的出现次数。因为是整段,也就是开头到结尾包含的都是整块,所以可以预处理一个前缀和 \(s[i][j]\) 表示前 \(i\) 块中 \(j\) 的出现次数就可以求出来了。
伤心,\(O((n+q)\sqrt n)\) 被 \(O((n+q)\sqrt n \log n)\) 吊打。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I> inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 1e5 + 7;
const int B = 316 + 7;
#define bl(x) (((x) - 1) / blo + 1)
#define st(x) (((x) - 1) * blo + 1)
#define ed(x) std::min((x) * blo, n)
int n, dis, Q, blo;
int a[N], b[N], s[B][N], cnt[N];
ll f[B][N];
inline void ycl() {
for (int i = 1; i <= bl(n); ++i)
for (int j = st(i); j <= ed(i); ++j) ++s[i][a[j]];
for (int i = 1; i <= bl(n); ++i)
for (int j = 1; j <= dis; ++j) s[i][j] += s[i - 1][j];
for (int i = 1; i <= bl(n); ++i) {
memset(cnt, 0, sizeof(int) * (dis + 1));
int x = st(i);
ll mx = 0;
for (int j = x; j <= n; ++j) {
smax(mx, (ll)b[a[j]] * ++cnt[a[j]]);
f[i][j] = mx;
}
}
memset(cnt, 0, sizeof(int) * (dis + 1));
}
inline ll qry(int l, int r) {
ll ans = 0;
if (bl(l) == bl(r)) {
for (int i = l; i <= r; ++i) smax(ans, (ll)b[a[i]] * ++cnt[a[i]]);
for (int i = l; i <= r; ++i) cnt[a[i]] = 0;
return ans;
}
ans = f[bl(l) + 1][r];
int sl = bl(l) + 1, sr = bl(r) - 1;
for (int i = l; i <= ed(bl(l)); ++i) smax(ans, (ll)b[a[i]] * (++cnt[a[i]] + s[sr][a[i]] - s[sl - 1][a[i]]));
for (int i = st(bl(r)); i <= r; ++i) smax(ans, (ll)b[a[i]] * (++cnt[a[i]] + s[sr][a[i]] - s[sl - 1][a[i]]));
for (int i = l; i <= ed(bl(l)); ++i) cnt[a[i]] = 0;
for (int i = st(bl(r)); i <= r; ++i) cnt[a[i]] = 0;
return ans;
}
inline void lsh() {
std::sort(b + 1, b + n + 1);
dis = std::unique(b + 1, b + n + 1) - b - 1;
for (int i = 1; i <= n; ++i) a[i] = std::lower_bound(b + 1, b + dis + 1, a[i]) - b;
}
inline void work() {
lsh();
ycl();
while (Q--) {
int l, r;
read(l), read(r);
printf("%lld\n", qry(l, r));
}
}
inline void init() {
read(n), read(Q);
blo = sqrt(n);
for (int i = 1; i <= n; ++i) read(a[i]), b[i] = a[i];
}
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}