[Ynoi2019 模擬賽] Yuno loves sqrt technology III
阿新 • • 發佈:2021-07-19
題面
Yuno loves sqrt technology III
題解
一道很水的黑題。
做過蒲公英的同學應該都知道這和蒲公英很類似。
不同的是它維護的是區間眾數的個數。
因為區間眾數不具有可加性,再加上強制線上,顯然是用分塊來維護。
首先正常分塊。
預處理塊內資訊時的整合就直接 \(\sqrt(n) ^ 3\) 暴力列舉,得到塊 \(l\) 到 塊 \(r\) 的區間眾數個數。
對於詢問就和正常分塊相同,暴力處理兩邊零散的情況。
但不同於蒲公英的是,這道題資料範圍更大些,再加一個 \(logn\) 的二分查詢,顯然是不行的。
所以我們需要找到一個更快的處理方法。
記錄 \(a[i]\) 在數值 \(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; }