洛谷P4168 [Violet]蒲公英 題解 數列分塊
阿新 • • 發佈:2021-11-09
題目大意:對大小為 \(n\) 的數列進行 \(m\) ,每次求出區間最小眾數。
解題思路:數列分塊。同:LOJ6285. 數列分塊入門 9
示例程式:
#include <bits/stdc++.h> using namespace std; const int maxn = 40040; int n, m, blo, id, a[maxn], bl[maxn], p[202][202]; map<int, int> mp; int val[maxn], cnt[maxn]; vector<int> g[maxn]; void pre(int x) { memset(cnt, 0, sizeof(cnt)); int res = 0, mx = 0; for (int i = (x-1)*blo+1; i <= n; i ++) { cnt[a[i]] ++; int t = bl[i]; if (cnt[a[i]] > mx || cnt[a[i]] == mx && val[a[i]] < val[res]) { res = a[i]; mx = cnt[a[i]]; } p[x][t] = res; } } int mycount(int l, int r, int x) { return upper_bound(g[x].begin(), g[x].end(), r) - lower_bound(g[x].begin(), g[x].end(), l); } int query(int l, int r) { int res = p[bl[l]+1][bl[r]-1], mx = mycount(l, r, res); for (int i = l; i <= min(bl[l]*blo, r); i ++) { int t = mycount(l, r, a[i]); if (t > mx || t == mx && val[a[i]] < val[res]) { res = a[i]; mx = t; } } if (bl[l] != bl[r]) { for (int i = (bl[r]-1)*blo+1; i <= r; i ++) { int t = mycount(l, r, a[i]); if (t > mx || t == mx && val[a[i]] < val[res]) { res = a[i]; mx = t; } } } return res; } int main() { ios::sync_with_stdio(0); cin >> n >> m; blo = sqrt(n); for (int i = 1; i <= n; i ++) { cin >> a[i]; bl[i] = (i - 1) / blo + 1; if (!mp[a[i]]) { mp[a[i]] = ++id; val[id] = a[i]; } a[i] = mp[a[i]]; g[a[i]].push_back(i); } for (int i = 1; i <= bl[n]; i ++) pre(i); int l, r, x = 0; for (int i = 1; i <= m; i ++) { int l0, r0; cin >> l0 >> r0; l = (l0 + x -1) % n + 1; r = (r0 + x - 1) % n + 1; if (l > r) swap(l, r); x = val[query(l, r)]; cout << x << endl; } return 0; }