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})$

仕様

template <typename AddLeft, typename AddRight,
          typename DelLeft, typename DelRight>
struct Mo;

メンバ関数

名前 効果・戻り値 備考
explicit Mo(const std::vector<int>& ls, const std::vector<int>& rs, const AddLeft& add_left, const AddRight& add_right, const DelLeft& del_left, const DelRight& del_right); クエリ集合 $\lbrace \lbrack \mathrm{ls}_i, \mathrm{rs}_i) \rbrace$ と、区間の左端・右端に対する追加・削除をそれぞれ指定してオブジェクトを構築する。  
int process(); 次のクエリを処理し、そのインデックスを返す。ただし存在しないときは $-1$ を返す。  

参考文献

TODO

Submissons

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

Required by

Verified with

Code

#ifndef EMTHRM_MISC_MO_HPP_
#define EMTHRM_MISC_MO_HPP_

#include <algorithm>
#include <cmath>
#include <numeric>
#include <vector>

namespace emthrm {

template <typename AddLeft, typename AddRight,
          typename DelLeft, typename DelRight>
struct Mo {
  explicit Mo(const std::vector<int>& ls, const std::vector<int>& rs,
              const AddLeft& add_left, const AddRight& add_right,
              const DelLeft& del_left, const DelRight& del_right)
      : n(ls.size()), ptr(0), nl(0), nr(0), ls(ls), rs(rs),
        add_left(add_left), add_right(add_right),
        del_left(del_left), del_right(del_right) {
    const int width = (
        n == 0 ? 1
               : std::max(std::llround(std::ranges::max(rs) / std::sqrt(n)),
                          1LL));
    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) {
      const int idx = --nl;
      add_left(idx, nl, nr);
    }
    while (nr < rs[id]) {
      const int idx = nr++;
      add_right(idx, nl, nr);
    }
    while (nl < ls[id]) {
      const int idx = nl++;
      del_left(idx, nl, nr);
    }
    while (rs[id] < nr) {
      const int idx = --nr;
      del_right(idx, nl, nr);
    }
    return id;
  }

 private:
  const int n;
  int ptr, nl, nr;
  std::vector<int> ls, rs, order;
  AddLeft add_left;
  AddRight add_right;
  DelLeft del_left;
  DelRight del_right;
};

}  // namespace emthrm

#endif  // EMTHRM_MISC_MO_HPP_
#line 1 "include/emthrm/misc/mo.hpp"



#include <algorithm>
#include <cmath>
#include <numeric>
#include <vector>

namespace emthrm {

template <typename AddLeft, typename AddRight,
          typename DelLeft, typename DelRight>
struct Mo {
  explicit Mo(const std::vector<int>& ls, const std::vector<int>& rs,
              const AddLeft& add_left, const AddRight& add_right,
              const DelLeft& del_left, const DelRight& del_right)
      : n(ls.size()), ptr(0), nl(0), nr(0), ls(ls), rs(rs),
        add_left(add_left), add_right(add_right),
        del_left(del_left), del_right(del_right) {
    const int width = (
        n == 0 ? 1
               : std::max(std::llround(std::ranges::max(rs) / std::sqrt(n)),
                          1LL));
    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) {
      const int idx = --nl;
      add_left(idx, nl, nr);
    }
    while (nr < rs[id]) {
      const int idx = nr++;
      add_right(idx, nl, nr);
    }
    while (nl < ls[id]) {
      const int idx = nl++;
      del_left(idx, nl, nr);
    }
    while (rs[id] < nr) {
      const int idx = --nr;
      del_right(idx, nl, nr);
    }
    return id;
  }

 private:
  const int n;
  int ptr, nl, nr;
  std::vector<int> ls, rs, order;
  AddLeft add_left;
  AddRight add_right;
  DelLeft del_left;
  DelRight del_right;
};

}  // namespace emthrm
Back to top page