LG P5048 [Ynoi2019 模拟赛] Yuno loves sqrt technology III Solution
Description
给定序列 a = ( a 1 , a 2 , ⋯ , a n ) a=(a_1,a_2,\cdots,a_n) a=(a1,a2,⋯,an), q q q 次查询 ( l , r ) (l,r) (l,r),求 a l ∼ a r a_l\sim a_r al∼ar 间的众数出现次数.
本题强制在线,每次给定 l ′ , r ′ l^\prime,r^\prime l′,r′,需要 xor \operatorname{xor} xor 上上一次答案得到 l , r l,r l,r,没有则为 0 0 0.
Limitations
1 ≤ n , m , a i ≤ 5 × 10 5 1\le n,m,a_i\le 5\times 10^5 1≤n,m,ai≤5×105
1 ≤ l ≤ r ≤ n 1\le l\le r\le n 1≤l≤r≤n
2 s , 62.5 MB 2\text{s},\textcolor{red}{62.5\text{MB}} 2s,62.5MB.
Solution
类似 P4168,先预处理出 f l , r f_{l,r} fl,r 表示第 l ∼ r l\sim r l∼r 块间的答案.
现在只需考虑散块,由于空间问题,不能套用 P4168
的做法.
设整块内答案为 res \textit{res} res,若散块中有更优答案,其在 a l ∼ a r a_l\sim a_r al∼ar 间出现次数一定大于 res \textit{res} res.
考虑左散块内每个数 a i a_i ai,设 p i p_i pi 表示 a i a_i ai 在 a 1 ∼ a i a_1\sim a_i a1∼ai 的出现次数,若 a i a_i ai 的第 ( p i + res ) (p_i+\textit{res}) (pi+res) 次出现仍在 [ l , r ] [l,r] [l,r] 内,那么 a i a_i ai 更优, res \textit{res} res 加一,重复进行直到不满足以上条件.(右散块同理)
而 a i a_i ai 在 a a a 中所有出现位置下标显然可用 vector
存(空间复杂度为 O ( n ) O(n) O(n)),于是做完了,注意几点:
vector
下标从 0 0 0 开始.- 块长开大到 800 800 800 左右.
- 离散化以节省空间.
由于散块内 res \textit{res} res 最多自增 2 n 2\sqrt n 2n 次,时间复杂度为 O ( n n ) O(n\sqrt n) O(nn).
Code
3.22 KB , 5.42 s , 11.91 MB (in total, C++20 with O2) 3.22\text{KB},5.42\text{s},11.91\text{MB}\;\texttt{(in total, C++20 with O2)} 3.22KB,5.42s,11.91MB(in total, C++20 with O2)
#include <bits/stdc++.h>
using namespace std;using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;template<class T>
bool chmax(T &a, const T &b){if(a < b){ a = b; return true; }return false;
}template<class T>
bool chmin(T &a, const T &b){if(a > b){ a = b; return true; }return false;
}namespace fastio {} // By pystraf
using fastio::read;
using fastio::write;template<int B>
struct Block {int n, v, blocks;vector<vector<int>> f;vector<basic_string<int>> pos;vector<int> cnt, p;inline Block() {}inline Block(int _n, int _v) : n(_n), v(_v) {blocks = (n + B - 1) / B;f.resize(blocks, vector<int>(blocks, 0));cnt.resize(v), pos.resize(v), p.resize(n);}inline int bel(int x) { return x / B; }inline int L(int x) { return x * B; }inline int R(int x) { return min(L(x) + B, n) - 1; }inline void clear(int l, int r, const vector<int>& a) {for (int i = l; i <= r; i++) cnt[a[i]] = 0;}inline void init(const vector<int>& a) {for (int i = 0; i < n; i++) {p[i] = pos[a[i]].size();pos[a[i]] += i;}for (int i = 0; i < blocks; i++) {for (int j = i; j < blocks; j++) {if (j > i) f[i][j] = f[i][j - 1];const int bl = L(j), br = R(j);for (int k = bl; k <= br; k++) chmax(f[i][j], ++cnt[a[k]]);}clear(L(i), n - 1, a);}}inline int query(int l, int r, const vector<int>& a) {const int bl = bel(l), br = bel(r);if (bl == br) {int res = 0;for (int i = l; i <= r; i++) chmax(res, ++cnt[a[i]]);clear(l, r, a);return res;}const int lt = R(bl), rt = L(br);int res = f[bl + 1][br - 1];for (int i = l; i <= lt; i++) while (res + p[i] < pos[a[i]].size() && pos[a[i]][res + p[i]] <= r) res++;for (int i = rt; i <= r; i++) while (p[i] - res >= 0 && pos[a[i]][p[i] - res] >= l) res++;return res;}
};constexpr int B = 800;signed main() {ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);const int n = read<int>(), m = read<int>();vector<int> a(n), b(n);for (int i = 0; i < n; i++) b[i] = a[i] = read<int>();sort(b.begin(), b.end());b.erase(unique(b.begin(), b.end()), b.end());for (int i = 0; i < n; i++) {a[i] = lower_bound(b.begin(), b.end(), a[i]) - b.begin();}Block<B> blk(n, b.size());blk.init(a);for (int i = 0, l, r, lst = 0; i < m; i++) {l = read<int>(), r = read<int>();l ^= lst, r ^= lst, l--, r--;if (l > r) swap(l, r);write(lst = blk.query(l, r, a));putchar_unlocked('\n');}return 0;
}