static_range_mode.hpp¶
预处理静态数组的区间众数查询,返回出现次数最多的值及频次。
Complexity: Time: O(n sqrt(n)) build and O(sqrt(n) log n) query. Space: O(n sqrt(n)).
AC 记录:static_range_mode_query。
Implementation¶
当前头文件,省略 include guard;依赖见 #include。
/// @complexity Time: O(n sqrt(n)) build and O(sqrt(n) log n) query.
/// Space: O(n sqrt(n)).
#include <algorithm>
#include <cassert>
#include <cmath>
#include <optional>
#include <utility>
#include <vector>
namespace noya {
/// @brief Static half-open range mode queries in O(sqrt(n) log n), with
/// O(n sqrt(n)) preprocessing; ties return the smallest value.
template <class T> struct static_range_mode {
int n = 0;
int bs = 1;
int nb = 0;
std::vector<T> xs;
std::vector<int> rk;
std::vector<std::vector<int>> pos;
std::vector<std::vector<int>> md;
static_range_mode() = default;
explicit static_range_mode(const std::vector<T> &a) { build(a); }
void build(const std::vector<T> &a) {
n = int(a.size());
bs = std::max(1, int(std::sqrt(std::max(1, n))));
nb = (n + bs - 1) / bs;
xs = a;
std::sort(xs.begin(), xs.end());
xs.erase(std::unique(xs.begin(), xs.end()), xs.end());
rk.resize(n);
pos.assign(xs.size(), {});
for (int idx = 0; idx < n; idx++) {
rk[idx] =
int(std::lower_bound(xs.begin(), xs.end(), a[idx]) - xs.begin());
pos[rk[idx]].push_back(idx);
}
md.assign(nb, std::vector<int>(nb, -1));
std::vector<int> cnt(xs.size());
for (int lb = 0; lb < nb; lb++) {
std::fill(cnt.begin(), cnt.end(), 0);
int bst = -1;
for (int idx = lb * bs; idx < n; idx++) {
int val = rk[idx];
cnt[val]++;
if (bst == -1 || cnt[val] > cnt[bst] ||
(cnt[val] == cnt[bst] && val < bst)) {
bst = val;
}
int rb = idx / bs;
md[lb][rb] = bst;
}
}
}
/// @brief Return (mode, frequency), or nullopt for an empty range.
std::optional<std::pair<T, int>> query(int l, int r) const {
assert(0 <= l && l <= r && r <= n);
if (l == r) {
return std::nullopt;
}
int fl = (l + bs - 1) / bs;
int fr = r / bs;
std::vector<int> cs;
if (fl < fr) {
cs.push_back(md[fl][fr - 1]);
}
int le = std::min(r, fl * bs);
for (int idx = l; idx < le; idx++) {
cs.push_back(rk[idx]);
}
int rl = std::max(le, fr * bs);
for (int idx = rl; idx < r; idx++) {
cs.push_back(rk[idx]);
}
std::sort(cs.begin(), cs.end());
cs.erase(std::unique(cs.begin(), cs.end()), cs.end());
int bst = cs[0];
int bc = -1;
for (int can : cs) {
const auto &vec = pos[can];
int cnt = int(std::lower_bound(vec.begin(), vec.end(), r) -
std::lower_bound(vec.begin(), vec.end(), l));
if (cnt > bc || (cnt == bc && can < bst)) {
bst = can;
bc = cnt;
}
}
return std::pair<T, int>{xs[bst], bc};
}
};
} // namespace noya
#ifndef NOYA_STATIC_RANGE_MODE_HPP
#define NOYA_STATIC_RANGE_MODE_HPP 1
/// @complexity Time: O(n sqrt(n)) build and O(sqrt(n) log n) query.
/// Space: O(n sqrt(n)).
#include <algorithm>
#include <cassert>
#include <cmath>
#include <optional>
#include <utility>
#include <vector>
namespace noya {
/// @brief Static half-open range mode queries in O(sqrt(n) log n), with
/// O(n sqrt(n)) preprocessing; ties return the smallest value.
template <class T> struct static_range_mode {
int n = 0;
int bs = 1;
int nb = 0;
std::vector<T> xs;
std::vector<int> rk;
std::vector<std::vector<int>> pos;
std::vector<std::vector<int>> md;
static_range_mode() = default;
explicit static_range_mode(const std::vector<T> &a) { build(a); }
void build(const std::vector<T> &a) {
n = int(a.size());
bs = std::max(1, int(std::sqrt(std::max(1, n))));
nb = (n + bs - 1) / bs;
xs = a;
std::sort(xs.begin(), xs.end());
xs.erase(std::unique(xs.begin(), xs.end()), xs.end());
rk.resize(n);
pos.assign(xs.size(), {});
for (int idx = 0; idx < n; idx++) {
rk[idx] =
int(std::lower_bound(xs.begin(), xs.end(), a[idx]) - xs.begin());
pos[rk[idx]].push_back(idx);
}
md.assign(nb, std::vector<int>(nb, -1));
std::vector<int> cnt(xs.size());
for (int lb = 0; lb < nb; lb++) {
std::fill(cnt.begin(), cnt.end(), 0);
int bst = -1;
for (int idx = lb * bs; idx < n; idx++) {
int val = rk[idx];
cnt[val]++;
if (bst == -1 || cnt[val] > cnt[bst] ||
(cnt[val] == cnt[bst] && val < bst)) {
bst = val;
}
int rb = idx / bs;
md[lb][rb] = bst;
}
}
}
/// @brief Return (mode, frequency), or nullopt for an empty range.
std::optional<std::pair<T, int>> query(int l, int r) const {
assert(0 <= l && l <= r && r <= n);
if (l == r) {
return std::nullopt;
}
int fl = (l + bs - 1) / bs;
int fr = r / bs;
std::vector<int> cs;
if (fl < fr) {
cs.push_back(md[fl][fr - 1]);
}
int le = std::min(r, fl * bs);
for (int idx = l; idx < le; idx++) {
cs.push_back(rk[idx]);
}
int rl = std::max(le, fr * bs);
for (int idx = rl; idx < r; idx++) {
cs.push_back(rk[idx]);
}
std::sort(cs.begin(), cs.end());
cs.erase(std::unique(cs.begin(), cs.end()), cs.end());
int bst = cs[0];
int bc = -1;
for (int can : cs) {
const auto &vec = pos[can];
int cnt = int(std::lower_bound(vec.begin(), vec.end(), r) -
std::lower_bound(vec.begin(), vec.end(), l));
if (cnt > bc || (cnt == bc && can < bst)) {
bst = can;
bc = cnt;
}
}
return std::pair<T, int>{xs[bst], bc};
}
};
} // namespace noya
#endif // NOYA_STATIC_RANGE_MODE_HPP
#include <algorithm>
#include <cassert>
#include <cmath>
#include <optional>
#include <utility>
#include <vector>
/// @complexity Time: O(n sqrt(n)) build and O(sqrt(n) log n) query.
/// Space: O(n sqrt(n)).
namespace noya {
/// @brief Static half-open range mode queries in O(sqrt(n) log n), with
/// O(n sqrt(n)) preprocessing; ties return the smallest value.
template <class T> struct static_range_mode {
int n = 0;
int bs = 1;
int nb = 0;
std::vector<T> xs;
std::vector<int> rk;
std::vector<std::vector<int>> pos;
std::vector<std::vector<int>> md;
static_range_mode() = default;
explicit static_range_mode(const std::vector<T> &a) { build(a); }
void build(const std::vector<T> &a) {
n = int(a.size());
bs = std::max(1, int(std::sqrt(std::max(1, n))));
nb = (n + bs - 1) / bs;
xs = a;
std::sort(xs.begin(), xs.end());
xs.erase(std::unique(xs.begin(), xs.end()), xs.end());
rk.resize(n);
pos.assign(xs.size(), {});
for (int idx = 0; idx < n; idx++) {
rk[idx] =
int(std::lower_bound(xs.begin(), xs.end(), a[idx]) - xs.begin());
pos[rk[idx]].push_back(idx);
}
md.assign(nb, std::vector<int>(nb, -1));
std::vector<int> cnt(xs.size());
for (int lb = 0; lb < nb; lb++) {
std::fill(cnt.begin(), cnt.end(), 0);
int bst = -1;
for (int idx = lb * bs; idx < n; idx++) {
int val = rk[idx];
cnt[val]++;
if (bst == -1 || cnt[val] > cnt[bst] ||
(cnt[val] == cnt[bst] && val < bst)) {
bst = val;
}
int rb = idx / bs;
md[lb][rb] = bst;
}
}
}
/// @brief Return (mode, frequency), or nullopt for an empty range.
std::optional<std::pair<T, int>> query(int l, int r) const {
assert(0 <= l && l <= r && r <= n);
if (l == r) {
return std::nullopt;
}
int fl = (l + bs - 1) / bs;
int fr = r / bs;
std::vector<int> cs;
if (fl < fr) {
cs.push_back(md[fl][fr - 1]);
}
int le = std::min(r, fl * bs);
for (int idx = l; idx < le; idx++) {
cs.push_back(rk[idx]);
}
int rl = std::max(le, fr * bs);
for (int idx = rl; idx < r; idx++) {
cs.push_back(rk[idx]);
}
std::sort(cs.begin(), cs.end());
cs.erase(std::unique(cs.begin(), cs.end()), cs.end());
int bst = cs[0];
int bc = -1;
for (int can : cs) {
const auto &vec = pos[can];
int cnt = int(std::lower_bound(vec.begin(), vec.end(), r) -
std::lower_bound(vec.begin(), vec.end(), l));
if (cnt > bc || (cnt == bc && can < bst)) {
bst = can;
bc = cnt;
}
}
return std::pair<T, int>{xs[bst], bc};
}
};
} // namespace noya