Skip to content

parallel_binary_search.hpp

SECTIONOptimization INCLUDEnoya/parallel_binary_search.hpp

把多组答案同时在同一串更新前缀上二分;适合判定随时间单调、可批量重放更新的离线题。

Complexity: Time: O((U + Q) log U) callback work for U update positions. Space: O(Q).

跳到代码 · GitHub ↗

Implementation

当前头文件,省略 include guard;依赖见 #include

/// @complexity Time: O((U + Q) log U) callback work for U update positions.
/// Space: O(Q).

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <numeric>
#include <vector>

namespace noya {

/// @brief Run parallel binary search over prefixes of a common update list.
/// `ok` must be a known true boundary and `ng` a known false boundary. Calling
/// che(q) after t calls to upd represents the predicate at prefix t.
template <class Reset, class Update, class Check>
std::vector<int> parallel_binary_search(int nq, int ok, int ng, Reset res,
                                        Update upd, Check che) {
  assert(nq >= 0);
  int nu = std::max(ok, ng);
  assert(std::min(ok, ng) >= -1);
  std::vector<int> hi(nq, ok);
  std::vector<int> lo(nq, ng);
  while (true) {
    std::vector<std::vector<int>> buc(nu + 1);
    int rem = 0;
    for (int que = 0; que < nq; que++) {
      if (std::llabs(static_cast<long long>(hi[que]) - lo[que]) <= 1) {
        continue;
      }
      int mid = std::midpoint(hi[que], lo[que]);
      assert(0 <= mid && mid <= nu);
      buc[mid].push_back(que);
      rem++;
    }
    if (rem == 0) {
      break;
    }

    res();
    int app = 0;
    for (int pre = 0; pre <= nu; pre++) {
      while (app < pre) {
        upd(app++);
      }
      for (int que : buc[pre]) {
        if (che(que)) {
          hi[que] = pre;
        } else {
          lo[que] = pre;
        }
      }
    }
  }
  return hi;
}

} // namespace noya
#ifndef NOYA_PARALLEL_BINARY_SEARCH_HPP
#define NOYA_PARALLEL_BINARY_SEARCH_HPP 1

/// @complexity Time: O((U + Q) log U) callback work for U update positions.
/// Space: O(Q).

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <numeric>
#include <vector>

namespace noya {

/// @brief Run parallel binary search over prefixes of a common update list.
/// `ok` must be a known true boundary and `ng` a known false boundary. Calling
/// che(q) after t calls to upd represents the predicate at prefix t.
template <class Reset, class Update, class Check>
std::vector<int> parallel_binary_search(int nq, int ok, int ng, Reset res,
                                        Update upd, Check che) {
  assert(nq >= 0);
  int nu = std::max(ok, ng);
  assert(std::min(ok, ng) >= -1);
  std::vector<int> hi(nq, ok);
  std::vector<int> lo(nq, ng);
  while (true) {
    std::vector<std::vector<int>> buc(nu + 1);
    int rem = 0;
    for (int que = 0; que < nq; que++) {
      if (std::llabs(static_cast<long long>(hi[que]) - lo[que]) <= 1) {
        continue;
      }
      int mid = std::midpoint(hi[que], lo[que]);
      assert(0 <= mid && mid <= nu);
      buc[mid].push_back(que);
      rem++;
    }
    if (rem == 0) {
      break;
    }

    res();
    int app = 0;
    for (int pre = 0; pre <= nu; pre++) {
      while (app < pre) {
        upd(app++);
      }
      for (int que : buc[pre]) {
        if (che(que)) {
          hi[que] = pre;
        } else {
          lo[que] = pre;
        }
      }
    }
  }
  return hi;
}

} // namespace noya

#endif // NOYA_PARALLEL_BINARY_SEARCH_HPP
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <numeric>
#include <vector>

/// @complexity Time: O((U + Q) log U) callback work for U update positions.
/// Space: O(Q).

namespace noya {

/// @brief Run parallel binary search over prefixes of a common update list.
/// `ok` must be a known true boundary and `ng` a known false boundary. Calling
/// che(q) after t calls to upd represents the predicate at prefix t.
template <class Reset, class Update, class Check>
std::vector<int> parallel_binary_search(int nq, int ok, int ng, Reset res,
                                        Update upd, Check che) {
  assert(nq >= 0);
  int nu = std::max(ok, ng);
  assert(std::min(ok, ng) >= -1);
  std::vector<int> hi(nq, ok);
  std::vector<int> lo(nq, ng);
  while (true) {
    std::vector<std::vector<int>> buc(nu + 1);
    int rem = 0;
    for (int que = 0; que < nq; que++) {
      if (std::llabs(static_cast<long long>(hi[que]) - lo[que]) <= 1) {
        continue;
      }
      int mid = std::midpoint(hi[que], lo[que]);
      assert(0 <= mid && mid <= nu);
      buc[mid].push_back(que);
      rem++;
    }
    if (rem == 0) {
      break;
    }

    res();
    int app = 0;
    for (int pre = 0; pre <= nu; pre++) {
      while (app < pre) {
        upd(app++);
      }
      for (int que : buc[pre]) {
        if (che(que)) {
          hi[que] = pre;
        } else {
          lo[que] = pre;
        }
      }
    }
  }
  return hi;
}

} // namespace noya