C++ Library for Competitive Programming
#include "emthrm/misc/mo.hpp"
上記の条件を満たすことによって区間に関するクエリを高速に処理できるアルゴリズムである。
一回の伸縮あたり $O(\alpha)$ 時間かかるとおくと $O(Q\log{Q} + \alpha N\sqrt{Q})$
struct Mo;
名前 | 効果・戻り値 | 備考 |
---|---|---|
explicit Mo(const std::vector<int>& ls, const std::vector<int>& rs); |
クエリ集合 $\lbrace \lbrack \mathrm{ls}_i, \mathrm{rs}_i) \rbrace$ のオブジェクトを構築する。 | |
int process(); |
現在のクエリのインデックス。ただし存在しないときは $-1$ を返す。 | |
void add(const int idx) const; |
$A_{\mathrm{idx}}$ をクエリの範囲に追加する。 | 関数プロトタイプ |
void del(const int idx) const; |
$A_{\mathrm{idx}}$ をクエリの範囲から削除する。 | 関数プロトタイプ |
https://judge.yosupo.jp/submission/17371
#ifndef EMTHRM_MISC_MO_HPP_
#define EMTHRM_MISC_MO_HPP_
#include <algorithm>
#include <cmath>
#include <numeric>
#include <vector>
namespace emthrm {
struct Mo {
explicit Mo(const std::vector<int>& ls, const std::vector<int>& rs)
: n(ls.size()), ptr(0), nl(0), nr(0), ls(ls), rs(rs) {
const int width = std::round(std::sqrt(n));
order.resize(n);
std::iota(order.begin(), order.end(), 0);
std::sort(order.begin(), order.end(),
[&ls, &rs, width](const int a, const int b) -> bool {
if (ls[a] / width != ls[b] / width) return ls[a] < ls[b];
return (ls[a] / width) & 1 ? rs[a] < rs[b] : rs[a] > rs[b];
});
}
int process() {
if (ptr == n) [[unlikely]] return -1;
const int id = order[ptr++];
while (ls[id] < nl) add(--nl);
while (nr < rs[id]) add(nr++);
while (nl < ls[id]) del(nl++);
while (rs[id] < nr) del(--nr);
return id;
}
void add(const int idx) const;
void del(const int idx) const;
private:
const int n;
int ptr, nl, nr;
std::vector<int> ls, rs, order;
};
} // namespace emthrm
#endif // EMTHRM_MISC_MO_HPP_
#line 1 "include/emthrm/misc/mo.hpp"
#include <algorithm>
#include <cmath>
#include <numeric>
#include <vector>
namespace emthrm {
struct Mo {
explicit Mo(const std::vector<int>& ls, const std::vector<int>& rs)
: n(ls.size()), ptr(0), nl(0), nr(0), ls(ls), rs(rs) {
const int width = std::round(std::sqrt(n));
order.resize(n);
std::iota(order.begin(), order.end(), 0);
std::sort(order.begin(), order.end(),
[&ls, &rs, width](const int a, const int b) -> bool {
if (ls[a] / width != ls[b] / width) return ls[a] < ls[b];
return (ls[a] / width) & 1 ? rs[a] < rs[b] : rs[a] > rs[b];
});
}
int process() {
if (ptr == n) [[unlikely]] return -1;
const int id = order[ptr++];
while (ls[id] < nl) add(--nl);
while (nr < rs[id]) add(nr++);
while (nl < ls[id]) del(nl++);
while (rs[id] < nr) del(--nr);
return id;
}
void add(const int idx) const;
void del(const int idx) const;
private:
const int n;
int ptr, nl, nr;
std::vector<int> ls, rs, order;
};
} // namespace emthrm