原题链接
在线求区间众数.
众数不满足“区间可加性”, 考虑分块:
设将长度为
N
N
N 的序列分成
T
T
T 块, 有
M
M
M 个询问.
对于每个询问
[
l
,
r
]
[l, r]
[l,r], 设
l
l
l 处于第
p
p
p 块, 设
r
r
r 处于第
q
q
q 块, 区间
[
l
,
r
]
[l, r]
[l,r] 分成
[
l
,
L
)
,
[
L
,
R
]
,
(
R
,
r
]
[l, L), [L, R], (R, r]
[l,L),[L,R],(R,r] 三部分, 其中
[
L
,
R
]
[L, R]
[L,R] 即为整个第
p
+
1
p+1
p+1~
q
−
1
q-1
q−1 块.
答案仅可能来自
[
L
,
R
]
[L, R]
[L,R] 的众数或出现在
[
l
,
L
)
[l, L)
[l,L) 与
(
R
,
r
]
(R, r]
(R,r] 之间的数.
法一:
-
预处理 c n t L , R cnt_{L, R} cntL,R 表示区间 [ L , R ] [L, R] [L,R] 中每个数出现的次数,并得出区间 [ L , R ] [L, R] [L,R] 内的众数,其中 L L L 是某一个块的左端点, R R R 是某一个块的右端点,这部分时间复杂度和空间复杂度均为 O ( N T 2 ) O(NT^2) O(NT2).
-
对于每个询问的 [ l , L ) [l, L) [l,L) 和 ( R , r ] (R, r] (R,r], 在数组 c n t L , R cnt_{L, R} cntL,R 的基础上累加次数, 得到答案并把数组复原.
-
时间复杂度 O ( N T 2 + M N / T ) , T = M 3 O(NT^2 +MN/T), T=\sqrt[3]{M} O(NT2+MN/T),T=3M 时时间复杂度最优, 为 O ( N M 2 3 ) O(NM^\frac{2}{3}) O(NM32). N , M N, M N,M 同阶时 T = N 3 T=\sqrt[3]{N} T=3N, 时间复杂度 O ( N 5 3 ) O(N^\frac{5}{3}) O(N35).
法二:
- 预处理区间 [ L , R ] [L, R] [L,R] 的众数,其中 L L L 是某一个块的左端点, R R R 是某一个块的右端点.
- 对每个数值建 v e c t o r vector vector, 保存该数值的出现位置.
- 二分查找每个可能答案在询问区间的出现次数.
- 时间复杂度 O ( N T + M N / T log N ) , T = M log N O(NT+MN/T\log{N}),T=\sqrt{M\log{N}} O(NT+MN/TlogN),T=MlogN时时间复杂度最优,为 O ( N M log N ) O(N\sqrt{M\log{N}}) O(NMlogN), N , M N, M N,M 同阶时 T = N log N T=\sqrt{N\log{N}} T=NlogN, 时间复杂度 O ( N N log N ) O(N\sqrt{N\log{N}}) O(NNlogN).
法三:
- 预处理每个块的众数.
- 对每个数值建 v e c t o r vector vector, 保存该数值的出现位置.
- 二分查找每个可能答案在询问区间的出现次数.
- 时间复杂度 O ( N + M ( N / T + T ) log N ) , T = N O(N+M(N/T+T)\log{N}),T=\sqrt{N} O(N+M(N/T+T)logN),T=N时时间复杂度最优,为 O ( N + M N log N ) O(N+M\sqrt{N}\log{N}) O(N+MNlogN), N , M N, M N,M 同阶时时间复杂度 O ( N N log N ) O(N\sqrt{N}\log{N}) O(NNlogN).
代码如下:
法一:
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int x = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f = ch == '-', ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
const int N = 40010, T = 40;
int n, m, a[N], tmp[N], cnt[T][T][N], ans[T][T];
int l[N], r[N], pos[N], block;
int Query(int x, int y) {
int p = pos[x], q = pos[y], res = 0;
if (p == q) {
for (int i = x; i <= y; ++i) {
++cnt[0][0][a[i]];
if (cnt[0][0][a[i]] > cnt[0][0][res] || (cnt[0][0][a[i]] == cnt[0][0][res] && a[i] < res)) res = a[i];
}
for (int i = x; i <= y; ++i) {
--cnt[0][0][a[i]];
}
return res;
}
res = ans[p + 1][q - 1];
for (int i = x; i <= r[p]; ++i) {
++cnt[p + 1][q - 1][a[i]];
if (cnt[p + 1][q - 1][a[i]] > cnt[p + 1][q - 1][res] || (cnt[p + 1][q - 1][a[i]] == cnt[p + 1][q - 1][res] && a[i] < res)) res = a[i];
}
for (int i = l[q]; i <= y; ++i) {
++cnt[p + 1][q - 1][a[i]];
if (cnt[p + 1][q - 1][a[i]] > cnt[p + 1][q - 1][res] || (cnt[p + 1][q - 1][a[i]] == cnt[p + 1][q - 1][res] && a[i] < res)) res = a[i];
}
for (int i = x; i <= r[p]; ++i) {
--cnt[p + 1][q - 1][a[i]];
}
for (int i = l[q]; i <= y; ++i) {
--cnt[p + 1][q - 1][a[i]];
}
return res;
}
int main() {
n = read(); m = read();
block = cbrt(n);
for (int i = 1; i <= block; ++i) {
l[i] = (i - 1) * (n / block) + 1;
r[i] = i * (n / block);
}
if (r[block] < n) ++block, l[block] = r[block - 1] + 1, r[block] = n;
for (int i = 1; i <= n; ++i) a[i] = tmp[i] = read();
sort(tmp + 1, tmp + n + 1);
int len = unique(tmp + 1, tmp + n + 1) - (tmp + 1);
for (int i = 1; i <= n; ++i) {
a[i] = lower_bound(tmp + 1, tmp + len + 1, a[i]) - tmp;
}
for (int i = 1; i <= block; ++i) {
for (int j = l[i]; j <= r[i]; ++j) {
pos[j] = i;
}
}
for (int i = 1; i <= block; ++i) {
for (int j = i; j <= block; ++j) {
for (int k = l[i]; k <= r[j]; ++k) {
++cnt[i][j][a[k]];
if (cnt[i][j][a[k]] > cnt[i][j][ans[i][j]] || (cnt[i][j][a[k]] == cnt[i][j][ans[i][j]] && a[k] < ans[i][j])) ans[i][j] = a[k];
}
}
}
int la = 0;
while (m--) {
int x = ((read() + la - 1) % n) + 1, y = ((read() + la - 1) % n) + 1;
if (x > y) swap(x, y);
printf("%d\n", la = tmp[Query(x, y)]);
}
return 0;
}
法二:
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int x = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f = ch == '-', ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
const int N = 40010, T = 3710;
int n, m, a[N], tmp[N];
int block, l[N], r[N], pos[N];
int cnt[N], ans[T][T];
vector<int> vis[N];
int Query(int x, int y) {
int p = pos[x], q = pos[y], res = 0, pp = 0;
if (p == q) {
for (int i = x; i <= y; ++i) {
int left = lower_bound(vis[a[i]].begin(), vis[a[i]].end(), x) - vis[a[i]].begin(),
right = upper_bound(vis[a[i]].begin(), vis[a[i]].end(), y) - vis[a[i]].begin() - 1;
int len = right - left + 1;
if (len > pp || (len == pp && a[i] < res)) res = a[i], pp = len;
}
return res;
}
for (int i = x; i <= r[p]; ++i) {
int left = lower_bound(vis[a[i]].begin(), vis[a[i]].end(), x) - vis[a[i]].begin(),
right = upper_bound(vis[a[i]].begin(), vis[a[i]].end(), y) - vis[a[i]].begin() - 1;
int len = right - left + 1;
if (len > pp || (len == pp && a[i] < res)) res = a[i], pp = len;
}
for (int i = l[q]; i <= y; ++i) {
int left = lower_bound(vis[a[i]].begin(), vis[a[i]].end(), x) - vis[a[i]].begin(),
right = upper_bound(vis[a[i]].begin(), vis[a[i]].end(), y) - vis[a[i]].begin() - 1;
int len = right - left + 1;
if (len > pp || (len == pp && a[i] < res)) res = a[i], pp = len;
}
if (q - p >= 2) {
int left = lower_bound(vis[ans[p + 1][q - 1]].begin(), vis[ans[p + 1][q - 1]].end(), x) - vis[ans[p + 1][q - 1]].begin(),
right = upper_bound(vis[ans[p + 1][q - 1]].begin(), vis[ans[p + 1][q - 1]].end(), y) - vis[ans[p + 1][q - 1]].begin() - 1;
int len = right - left + 1;
if (len > pp || (len == pp && ans[p + 1][q - 1] < res)) res = ans[p + 1][q - 1], pp = len;
}
return res;
}
int main() {
n = read(); m = read();
block = sqrt(m * ceil(log2(n)));
for (int i = 1; i <= block; ++i) {
l[i] = (i - 1) * (n / block) + 1;
r[i] = i * (n / block);
}
int lenn = (n / block);
while (r[block] < n) ++block, l[block] = r[block - 1] + 1, r[block] = min(n, block * lenn);
for (int i = 1; i <= block; ++i) {
for (int j = l[i]; j <= r[i]; ++j) {
pos[j] = i;
}
}
for (int i = 1; i <= n; ++i) tmp[i] = a[i] = read();
sort(tmp + 1, tmp + n + 1);
int len = unique(tmp + 1, tmp + n + 1) - (tmp + 1);
for (int i = 1; i <= n; ++i) {
a[i] = lower_bound(tmp + 1, tmp + len + 1, a[i]) - tmp;
vis[a[i]].push_back(i);
}
for (int i = 1; i <= block; ++i) {
memset(cnt, 0, sizeof cnt);
for (int j = i; j <= block; ++j) {
ans[i][j] = ans[i][j - 1];
for (int k = l[j]; k <= r[j]; ++k) {
++cnt[a[k]];
if (cnt[a[k]] > cnt[ans[i][j]] || (cnt[a[k]] == cnt[ans[i][j]] && a[k] < ans[i][j])) ans[i][j] = a[k];
}
}
}
int la = 0;
while (m--) {
int x = ((read() + la - 1) % n) + 1, y = ((read() + la - 1) % n) + 1;
if (x > y) swap(x, y);
printf("%d\n", la = tmp[Query(x, y)]);
}
return 0;
}