luogu P5048 [Ynoi2019 模拟赛] Yuno loves sqrt technology III

https://www.luogu.com.cn/problem/P5048

挺有启发性的一题,不错
首先第一步和蒲公英那题很像
S [ i ] [ j ] S[i][j] S[i][j]为第i块到第j块的众数出现次数

然后再开n个vector记录每个值出现的位置

考虑询问,先把整块的答案ans求出来

然后考虑左边的散块,看和它值相同的后ans个点位置是不是<=r,如果是ans++
这个用vector可以O(1)实现
右边散块同理,最多延伸根号个,做完了
代码不难实现

code:

#include<bits/stdc++.h>
#define N 500050
using namespace std;
int S[805][805], gs[N], a[N], b[N], pos[N], bel[N], n, m, blo;
vector<int> V[N];
int query(int l, int r) {
    if(bel[l] == bel[r]) {
        for(int i = l; i <= r; i ++) gs[a[i]] = 0;
        int ret = 0;
        for(int i = l; i <= r; i ++) ret = max(ret, ++ gs[a[i]]);
        return ret;
    }
    int ret = S[bel[l] + 1][bel[r] - 1];
    for(int i = l; i <= bel[l] * blo; i ++) {
        int j = pos[i];
        while(j + ret < V[a[i]].size() && V[a[i]][j + ret] <= r) ret ++;
    }
    for(int i = (bel[r] - 1) * blo + 1; i <= r; i ++) {
        int j = pos[i];
        while(j - ret >= 0 && V[a[i]][j - ret] >= l) ret ++;
    }
    return ret;
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]), b[i] = a[i];
    sort(b + 1, b + 1 + n);
    for(int i = 1; i <= n; i ++) a[i] = lower_bound(b + 1, b + 1 + n, a[i]) - b;
    
    blo = sqrt(n);
    for(int i = 1; i <= n; i ++) V[a[i]].push_back(i), pos[i] = V[a[i]].size() - 1, bel[i] = (i - 1) / blo + 1;
    
    for(int i = 1; i <= bel[n]; i ++) {
        memset(gs, 0, sizeof gs);
        for(int j = i; j <= bel[n]; j ++) {
            S[i][j] = S[i][j - 1];
            int l = (j - 1) * blo + 1, r = min(j * blo, n);
            for(int k = l; k <= r; k ++) S[i][j] = max(S[i][j], ++ gs[a[k]]);
        }
    }
    
    int lst = 0;
    while(m --) {
        int l, r;
        scanf("%d%d", &l, &r); l ^= lst, r ^= lst;
        if(l > r) swap(l, r);
        printf("%d\n", lst = query(l, r));
    }
    return 0;
}
/*
 4 2
 2 3 3 3
 2 4
 3 4
 */
posted @ 2021-08-30 19:38  lahlah  阅读(51)  评论(0编辑  收藏  举报