cp-library

C++ Library for Competitive Programming

View the Project on GitHub emthrm/cp-library

:heavy_check_mark: Mo's algorithm
(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}}$ をクエリの範囲から削除する。 関数プロトタイプ

参考文献

TODO

Submissons

https://judge.yosupo.jp/submission/17371

Verified with

Code

#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
Back to top page