This documentation is automatically generated by online-judge-tools/verification-helper
#include "other_algorithms/monotone_minima.hpp"
SMAWK()
関数は,monotone な $N \times M$ 行列,すなわち各行の最小値の位置が行を下るにつれ右に移動していくような行列について,各行の最小値の位置およびその値を $O((N + M) \log (N + M))$ で取得する.
SMAWK のライブラリと互換性があり,SMAWK が使用されている箇所は本関数で代替可能(最悪計算量のオーダーはこちらの方に log がつくが,問題によってはこちらの方が実測上速い).
例えば辺重みが Monge な $N$ 頂点の DAG で頂点 $0$ から各頂点への最短路重みを求めたいとき, $N$ 行 $N - 1$ 列の行列を $(j, i)$ 成分が「直前に頂点 $i$ を経由し頂点 $j$ に到達する場合の最短路重み」であるようなものとして定めると本関数が適用できる(SMAWK も適用できるが).
using T = long long;
T inf = 1LL << 60;
int N;
vector<T> dp(N, inf);
dp[0] = 0;
auto weight = [&](int s, int t) -> T { /* Implement */ };
const auto res = MonotoneMinima<T>(
N, N - 1, [&](int j, int i) -> T { return i < j ? dp[i] + weight(i, j) : inf; });
#pragma once
#include <cassert>
#include <functional>
#include <vector>
// finding minimum element for each row of N*M matrix
// Constraints: the solution is monotonically non-decreasing
// Complexity: O(NM logM)
// Reference:
// https://topcoder-g-hatena-ne-jp.jag-icpc.org/spaghetti_source/20120923/1348327542.html
// Verify: https://mofecoder.com/contests/monoxercon_202508/tasks/monoxercon_202508_k
template <class T>
std::vector<std::pair<int, T>>
MonotoneMinima(int N, int M, const std::function<T(int i, int j)> &weight) {
std::vector<std::pair<int, T>> minima(N);
auto rec = [&](auto &&self, int il, int ir, int jl, int jr) -> void {
if (il >= ir or jl >= jr) return;
const int im = (il + ir) / 2;
T w = weight(im, jl);
int j_argmin = jl;
for (int j = jl + 1; j < jr; ++j) {
if (T wt = weight(im, j); wt < w) w = wt, j_argmin = j;
}
minima[im] = {j_argmin, w};
self(self, il, im, jl, j_argmin + 1);
self(self, im + 1, ir, j_argmin, jr);
};
rec(rec, 0, N, 0, M);
return minima;
}
#line 2 "other_algorithms/monotone_minima.hpp"
#include <cassert>
#include <functional>
#include <vector>
// finding minimum element for each row of N*M matrix
// Constraints: the solution is monotonically non-decreasing
// Complexity: O(NM logM)
// Reference:
// https://topcoder-g-hatena-ne-jp.jag-icpc.org/spaghetti_source/20120923/1348327542.html
// Verify: https://mofecoder.com/contests/monoxercon_202508/tasks/monoxercon_202508_k
template <class T>
std::vector<std::pair<int, T>>
MonotoneMinima(int N, int M, const std::function<T(int i, int j)> &weight) {
std::vector<std::pair<int, T>> minima(N);
auto rec = [&](auto &&self, int il, int ir, int jl, int jr) -> void {
if (il >= ir or jl >= jr) return;
const int im = (il + ir) / 2;
T w = weight(im, jl);
int j_argmin = jl;
for (int j = jl + 1; j < jr; ++j) {
if (T wt = weight(im, j); wt < w) w = wt, j_argmin = j;
}
minima[im] = {j_argmin, w};
self(self, il, im, jl, j_argmin + 1);
self(self, im + 1, ir, j_argmin, jr);
};
rec(rec, 0, N, 0, M);
return minima;
}