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
*/