#line 1 "algorithm/monotone_minima.cpp"
/**
* @brief monotone minima
* @author えびちゃん
*/
#include <cstddef>
#include <utility>
#include <vector>
#line 1 "utility/make/fix_point.cpp"
/**
* @brief ラムダ式の再帰
* @author えびちゃん
*/
#ifndef H_make_fix_point
#define H_make_fix_point
#line 10 "utility/make/fix_point.cpp"
template <typename Fn>
class fix_point: Fn {
public:
explicit constexpr fix_point(Fn&& f) noexcept: Fn(std::forward<Fn>(f)) {}
template <typename... Args>
constexpr decltype(auto) operator ()(Args&&... args) const {
return Fn::operator ()(*this, std::forward<Args>(args)...);
}
};
template <typename Fn>
static inline constexpr decltype(auto) make_fix_point(Fn&& f) noexcept {
return fix_point<Fn>{std::forward<Fn>(f)};
}
#endif /* !defined(H_make_fix_point) */
#line 14 "algorithm/monotone_minima.cpp"
template <typename Fn>
auto monotone_minima(Fn&& f, size_t h, size_t w) {
using value_type = decltype(f(h, w));
std::vector<size_t> res(h);
make_fix_point([&](auto dfs, size_t hl, size_t hu, size_t wl, size_t wu) -> void {
if (hl >= hu) return;
size_t hm = (hl+hu) >> 1;
value_type min = f(hm, wl);
res[hm] = wl;
for (size_t j = wl+1; j < wu; ++j) {
value_type cur = f(hm, j);
if (cur < min) {
min = std::move(cur);
res[hm] = j;
}
}
if (hl == hm) return;
dfs(hl, hm, wl, res[hm]+1);
dfs(hm+1, hu, res[hm], wu);
})(0, h, 0, w);
return res;
}