题目-P5048 [Ynoi2019 模拟赛] Yuno loves sqrt technology III

问题分析

查询区间众数出现的次数, 尝试对区间进行分块

假设已经知道了区间内众数出现的次数 s s s, 那么只需要判断散列块中是否有哪个数字还能成为众数

对于每个数字记录出现的位置 v v v, v [ a [ i ] ] v[a[i]] v[a[i]]代表 a [ i ] a[i] a[i]出现的一些位置, p o s [ i ] pos[i] pos[i]代表 a [ i ] a[i] a[i] v [ a [ i ] ] v[a[i]] v[a[i]]中的索引

假设区间内众数出现的次数是 a n s ans ans

  • 枚举所有左侧散列块, 假设数值是 w w w, 那么只需要检查是否存在 v [ w ] [ p o s [ i ] + a n s ] ≤ r v[w][pos[i] + ans] \le r v[w][pos[i]+ans]r, 就可以更新 a n s ans ans, 也就是算上当前位置, w w w出现的次数是 a n s + 1 ans + 1 ans+1
  • 枚举右侧散列块, 假设数值是 w w w, 检查 v [ w ] [ p o s [ i ] − a n s ] ≥ l v[w][pos[i] - ans] \ge l v[w][pos[i]ans]l, 算上当前位置, w w w出现的次数是 a n s + 1 ans + 1 ans+1

算法步骤

  • 初始化分块, 对数据进行离散化
  • 暴力初始化 f f f数组

代码实现

#include <bits/stdc++.h>

using namespace std;

const int N = 5e5 + 10, M = 710;

int n, m, a[N];
vector<int> vec;
int bsize, bcnt, st[M], ed[M], b[N];
vector<int> v[N];
int pos[N], f[M][M], tot[N];

void init() {
   
    bsize = sqrt(n);
    bcnt = (n - 1) / bsize + 1;
    for (int i = 1; i <= bcnt; ++i) {
   
        st[i] = (i - 1) * bsize + 1;
        ed[i] = min(n, i * bsize);
    }
    for (int i = 1; i <= n; ++i) b[i] = (i - 1) / bsize + 1;
    sort(vec.begin(), vec.end());
    vec.erase(unique(vec.begin(), vec.end()), vec.end());
}

int find(int x) {
   
    return lower_bound(vec.begin(), vec.end(), x) - vec.begin();
}

int query(int l, int r) {
   
    int x = b[l], y = b[r];
    if (x == y) {
   
        int ans = 0;
        for (int i = l; i <= r; ++i) tot[a[i]] = 0;
        for (int i = l; i <= r; ++i) ans = max(ans, ++tot[a[i]]);
        return ans;
    }

    int ans = f[x + 1][y - 1];
    for (int i = l; i <= ed[x]; ++i) {
   
        int t = pos[i];
        if (i + t < v[a[i]].size() && v[a[i]][i + t] <= r) ans++;
    }
    for (int i = st[y]; i <= r; ++i) {
   
        int t = pos[i];
        if (t - ans >= 0 && v[a[i]][t - ans] >= l) ans++;
    }

    return ans;
}

int main() {
   
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> m;
    for (int i = 1; i <= n; ++i) cin >> a[i], vec.push_back(a[i]);
    init();

    for (int i = 1; i <= n; ++i) a[i] = find(a[i]);
    for (int i = 1; i <= n; ++i) {
   
        v[a[i]].push_back(i);
        pos[i] = v[a[i]].size();
        pos[i]--;
    }

    for (int i = 1; i <= bcnt; ++i) {
   
        memset(tot, 0, sizeof tot);
        for (int j = i; j <= bcnt; ++j) {
   
            f[i][j] = f[i][j - 1];
            for (int k = st[j]; k <= ed[j]; ++k) {
   
                f[i][j] = max(f[i][j], ++tot[a[k]]);
            }
        }
    }

    int last = 0;
    while (m--) {
   
        int l, r;
        cin >> l >> r;
        l ^= last, r ^= last;
        if (r < l) swap(l, r);
        int ans = query(l, r);
        cout << ans << '\n';
        last = ans;
    }

    return 0;
}