Nyaan's Library

This documentation is automatically generated by online-judge-tools/verification-helper

View on GitHub

:heavy_check_mark: math/stern-brocot-tree-binary-search.hpp

Depends on

Verified with

Code

#pragma once

#include <functional>
#include <utility>
using namespace std;

#include "stern-brocot-tree.hpp"

// 分子と分母が INF 以下である非負の既約分数のうち次のものを返す
// first : f(x) が false である最大の既約分数 x
// second : f(x) が true である最小の既約分数 x
// ただし
// - f(0) = true の場合は (0/1, 0/1) を返す
// - true になる分数が存在しない場合は (?, 1/0) を返す
// - INF = 0 の場合は (0/1, 1/0) を返す
template <typename I>
pair<pair<I, I>, pair<I, I>> binary_search_on_stern_brocot_tree(
    function<bool(pair<I, I>)> f, const I &INF) {
  // INF >= 0
  assert(0 <= INF);
  SternBrocotTreeNode<I> m;
  if (INF == 0) return {m.lower_bound(), m.upper_bound()};

  // INF 条件を超える or f(m) = return_value である
  auto over = [&](bool return_value) {
    return max(m.x, m.y) > INF or f(m.get()) == return_value;
  };

  if (f(make_pair(0, 1))) return {m.lower_bound(), m.lower_bound()};
  int go_left = over(true);
  for (; true; go_left ^= 1) {
    if (go_left) {
      // f(M) = true -> (L, M] に答えがある
      // (f(L * b + M) = false) or (INF 超え) になる b の最小は?
      I a = 1;
      for (; true; a *= 2) {
        m.go_left(a);
        if (over(false)) {
          m.go_parent(a);
          break;
        }
      }
      for (a /= 2; a != 0; a /= 2) {
        m.go_left(a);
        if (over(false)) m.go_parent(a);
      }
      m.go_left(1);
      if (max(m.get().first, m.get().second) > INF)
        return {m.lower_bound(), m.upper_bound()};
    } else {
      // f(M) = false -> (M, R] に答えがある
      // (f(M + R * b) = true) or (INF 超え) になる b の最小は?
      I a = 1;
      for (; true; a *= 2) {
        m.go_right(a);
        if (over(true)) {
          m.go_parent(a);
          break;
        }
      }
      for (a /= 2; a != 0; a /= 2) {
        m.go_right(a);
        if (over(true)) m.go_parent(a);
      }
      m.go_right(1);
      if (max(m.get().first, m.get().second) > INF)
        return {m.lower_bound(), m.upper_bound()};
    }
  }
}
#line 2 "math/stern-brocot-tree-binary-search.hpp"

#include <functional>
#include <utility>
using namespace std;

#line 2 "math/stern-brocot-tree.hpp"

#include <algorithm>
#include <cassert>
#include <vector>
using namespace std;

// x / y (x > 0, y > 0) を管理、デフォルトで 1 / 1
// 入力が互いに素でない場合は gcd を取って格納
// seq : (1, 1) から (x, y) へのパス。右の子が正/左の子が負
template <typename Int>
struct SternBrocotTreeNode {
  using Node = SternBrocotTreeNode;

  Int lx, ly, x, y, rx, ry;
  vector<Int> seq;

  SternBrocotTreeNode() : lx(0), ly(1), x(1), y(1), rx(1), ry(0) {}

  SternBrocotTreeNode(Int X, Int Y) : SternBrocotTreeNode() {
    assert(1 <= X && 1 <= Y);
    Int g = gcd(X, Y);
    X /= g, Y /= g;
    while (min(X, Y) > 0) {
      if (X > Y) {
        Int d = X / Y;
        X -= d * Y;
        go_right(d - (X == 0 ? 1 : 0));
      } else {
        Int d = Y / X;
        Y -= d * X;
        go_left(d - (Y == 0 ? 1 : 0));
      }
    }
  }
  SternBrocotTreeNode(const pair<Int, Int> &xy)
      : SternBrocotTreeNode(xy.first, xy.second) {}
  SternBrocotTreeNode(const vector<Int> &_seq) : SternBrocotTreeNode() {
    for (const Int &d : _seq) {
      assert(d != 0);
      if (d > 0) go_right(d);
      if (d < 0) go_left(d);
    }
    assert(seq == _seq);
  }

  // pair<Int, Int> 型で分数を get
  pair<Int, Int> get() const { return make_pair(x, y); }
  // 区間の下限
  pair<Int, Int> lower_bound() const { return make_pair(lx, ly); }
  // 区間の上限
  pair<Int, Int> upper_bound() const { return make_pair(rx, ry); }

  // 根からの深さ
  Int depth() const {
    Int res = 0;
    for (auto &s : seq) res += abs(s);
    return res;
  }
  // 左の子に d 進む
  void go_left(Int d = 1) {
    if (d <= 0) return;
    if (seq.empty() or seq.back() > 0) seq.push_back(0);
    seq.back() -= d;
    rx += lx * d, ry += ly * d;
    x = rx + lx, y = ry + ly;
  }
  // 右の子に d 進む
  void go_right(Int d = 1) {
    if (d <= 0) return;
    if (seq.empty() or seq.back() < 0) seq.push_back(0);
    seq.back() += d;
    lx += rx * d, ly += ry * d;
    x = rx + lx, y = ry + ly;
  }
  // 親の方向に d 進む
  // d 進めたら true, 進めなかったら false を返す
  bool go_parent(Int d = 1) {
    if (d <= 0) return true;
    while (d != 0) {
      if (seq.empty()) return false;
      Int d2 = min(d, abs(seq.back()));
      if (seq.back() > 0) {
        x -= rx * d2, y -= ry * d2;
        lx = x - rx, ly = y - ry;
        seq.back() -= d2;
      } else {
        x -= lx * d2, y -= ly * d2;
        rx = x - lx, ry = y - ly;
        seq.back() += d2;
      }
      d -= d2;
      if (seq.back() == 0) seq.pop_back();
      if (d2 == Int{0}) break;
    }
    return true;
  }
  // SBT 上の LCA
  static Node lca(const Node &lhs, const Node &rhs) {
    Node n;
    for (int i = 0; i < min<int>(lhs.seq.size(), rhs.seq.size()); i++) {
      Int val1 = lhs.seq[i], val2 = rhs.seq[i];
      if ((val1 < 0) != (val2 < 0)) break;
      if (val1 < 0) n.go_left(min(-val1, -val2));
      if (val1 > 0) n.go_right(min(val1, val2));
      if (val1 != val2) break;
    }
    return n;
  }
  friend ostream &operator<<(ostream &os, const Node &rhs) {
    os << "\n";
    os << "L : ( " << rhs.lx << ", " << rhs.ly << " )\n";
    os << "M : ( " << rhs.x << ", " << rhs.y << " )\n";
    os << "R : ( " << rhs.rx << ", " << rhs.ry << " )\n";
    os << "seq : {";
    for (auto &x : rhs.seq) os << x << ", ";
    os << "} \n";
    return os;
  }
  friend bool operator<(const Node &lhs, const Node &rhs) {
    return lhs.x * rhs.y < rhs.x * lhs.y;
  }
  friend bool operator==(const Node &lhs, const Node &rhs) {
    return lhs.x == rhs.x and lhs.y == rhs.y;
  }
};

/**
 *  @brief Stern-Brocot Tree
 */
#line 8 "math/stern-brocot-tree-binary-search.hpp"

// 分子と分母が INF 以下である非負の既約分数のうち次のものを返す
// first : f(x) が false である最大の既約分数 x
// second : f(x) が true である最小の既約分数 x
// ただし
// - f(0) = true の場合は (0/1, 0/1) を返す
// - true になる分数が存在しない場合は (?, 1/0) を返す
// - INF = 0 の場合は (0/1, 1/0) を返す
template <typename I>
pair<pair<I, I>, pair<I, I>> binary_search_on_stern_brocot_tree(
    function<bool(pair<I, I>)> f, const I &INF) {
  // INF >= 0
  assert(0 <= INF);
  SternBrocotTreeNode<I> m;
  if (INF == 0) return {m.lower_bound(), m.upper_bound()};

  // INF 条件を超える or f(m) = return_value である
  auto over = [&](bool return_value) {
    return max(m.x, m.y) > INF or f(m.get()) == return_value;
  };

  if (f(make_pair(0, 1))) return {m.lower_bound(), m.lower_bound()};
  int go_left = over(true);
  for (; true; go_left ^= 1) {
    if (go_left) {
      // f(M) = true -> (L, M] に答えがある
      // (f(L * b + M) = false) or (INF 超え) になる b の最小は?
      I a = 1;
      for (; true; a *= 2) {
        m.go_left(a);
        if (over(false)) {
          m.go_parent(a);
          break;
        }
      }
      for (a /= 2; a != 0; a /= 2) {
        m.go_left(a);
        if (over(false)) m.go_parent(a);
      }
      m.go_left(1);
      if (max(m.get().first, m.get().second) > INF)
        return {m.lower_bound(), m.upper_bound()};
    } else {
      // f(M) = false -> (M, R] に答えがある
      // (f(M + R * b) = true) or (INF 超え) になる b の最小は?
      I a = 1;
      for (; true; a *= 2) {
        m.go_right(a);
        if (over(true)) {
          m.go_parent(a);
          break;
        }
      }
      for (a /= 2; a != 0; a /= 2) {
        m.go_right(a);
        if (over(true)) m.go_parent(a);
      }
      m.go_right(1);
      if (max(m.get().first, m.get().second) > INF)
        return {m.lower_bound(), m.upper_bound()};
    }
  }
}
Back to top page