Skip to content

Commit

Permalink
[auto-verifier] docs commit c7dd77b
Browse files Browse the repository at this point in the history
  • Loading branch information
web-flow authored Oct 6, 2024
1 parent 9f71040 commit 0fc8c6c
Show file tree
Hide file tree
Showing 5 changed files with 334 additions and 5 deletions.
11 changes: 10 additions & 1 deletion index.md
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,9 @@ data:
path: other_algorithms/longest_increasing_subsequence.hpp
title: "Longest increasing subsequence \uFF08LIS, \u6700\u9577\u5897\u52A0\u90E8\
\u5206\u5217\uFF09"
- icon: ':heavy_check_mark:'
path: other_algorithms/monge_shortest_path.hpp
title: Shortest path of DAG with Monge weights
- icon: ':warning:'
path: other_algorithms/mos_algorithm.hpp
title: "Mo's algorithm \uFF08\u533A\u9593\u30AF\u30A8\u30EA\u306B\u95A2\u3059\
Expand All @@ -536,7 +539,7 @@ data:
title: "Slope trick \uFF08\u533A\u5206\u7DDA\u5F62\u51F8\u95A2\u6570\u306B\u95A2\
\u3059\u308B\u7279\u5B9A\u306E\u66F4\u65B0\u3092\u9AD8\u901F\u306B\u6271\u3046\
\u624B\u6CD5\uFF09"
- icon: ':warning:'
- icon: ':heavy_check_mark:'
path: other_algorithms/smawk.hpp
title: Totally Monotone Matrix Searching (SMAWK)
- name: random
Expand Down Expand Up @@ -1461,6 +1464,9 @@ data:
- icon: ':heavy_check_mark:'
path: other_algorithms/test/binary_lifting.yuki1013.test.cpp
title: other_algorithms/test/binary_lifting.yuki1013.test.cpp
- icon: ':heavy_check_mark:'
path: other_algorithms/test/concave_max_plus_convolution.test.cpp
title: other_algorithms/test/concave_max_plus_convolution.test.cpp
- icon: ':heavy_check_mark:'
path: other_algorithms/test/dual_slope_trick.yuki2114.test.cpp
title: other_algorithms/test/dual_slope_trick.yuki2114.test.cpp
Expand All @@ -1470,6 +1476,9 @@ data:
- icon: ':heavy_check_mark:'
path: other_algorithms/test/longest_increasing_subsequence.test.cpp
title: other_algorithms/test/longest_increasing_subsequence.test.cpp
- icon: ':heavy_check_mark:'
path: other_algorithms/test/monge_shortest_path.yuki705.test.cpp
title: other_algorithms/test/monge_shortest_path.yuki705.test.cpp
- icon: ':heavy_check_mark:'
path: other_algorithms/test/permutation_tree.yuki1720.test.cpp
title: other_algorithms/test/permutation_tree.yuki1720.test.cpp
Expand Down
140 changes: 140 additions & 0 deletions other_algorithms/monge_shortest_path.hpp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
---
data:
_extendedDependsOn: []
_extendedRequiredBy: []
_extendedVerifiedWith:
- icon: ':heavy_check_mark:'
path: other_algorithms/test/monge_shortest_path.yuki705.test.cpp
title: other_algorithms/test/monge_shortest_path.yuki705.test.cpp
_isVerificationFailed: false
_pathExtension: hpp
_verificationStatusIcon: ':heavy_check_mark:'
attributes:
links:
- https://noshi91.hatenablog.com/entry/2022/01/13/001217
- https://noshi91.hatenablog.com/entry/2023/02/18/005856
bundledCode: "#line 2 \"other_algorithms/monge_shortest_path.hpp\"\n#include <cassert>\n\
#include <vector>\n\n// Shortest path of Monge-weighted graph\n// Variant of LARSCH\
\ Algorithm: https://noshi91.hatenablog.com/entry/2023/02/18/005856\n// Complexity:\
\ O(n log n)\n//\n// Given a directed graph with n vertices and weighted edges\n\
// (w(i, j) = cost_callback(i, j) (i < j)),\n// this class calculates the shortest\
\ path from vertex 0 to all other vertices.\ntemplate <class Cost> struct monge_shortest_path\
\ {\n std::vector<Cost> dist; // dist[i] = shortest distance from 0 to i\n\
\ std::vector<int> amin; // amin[i] = previous vertex of i in the shortest\
\ path\n\n template <class F> void _check(int i, int k, F cost_callback) {\n\
\ if (i <= k) return;\n if (Cost c = dist[k] + cost_callback(k,\
\ i); c < dist[i]) dist[i] = c, amin[i] = k;\n }\n\n template <class F>\
\ void _rec_solve(int l, int r, F cost_callback) {\n if (r - l == 1) return;\n\
\n const int m = (l + r) / 2;\n for (int k = amin[l]; k <= amin[r];\
\ ++k) _check(m, k, cost_callback);\n\n _rec_solve(l, m, cost_callback);\n\
\ for (int k = l + 1; k <= m; ++k) _check(r, k, cost_callback);\n \
\ _rec_solve(m, r, cost_callback);\n }\n\n template <class F> Cost solve(int\
\ n, F cost_callback) {\n assert(n > 0);\n dist.resize(n);\n \
\ amin.assign(n, 0);\n\n dist[0] = Cost();\n for (int i = 1;\
\ i < n; ++i) dist[i] = cost_callback(0, i);\n\n _rec_solve(0, n - 1, cost_callback);\n\
\n return dist.back();\n }\n\n template <class F> int num_edges()\
\ const {\n int ret = 0;\n for (int c = (int)amin.size() - 1; c\
\ >= 0; c = amin[c]) ++ret;\n return ret;\n }\n};\n\n// Find shortest\
\ path length from 0 to n - 1 with k edges, min_edges <= k <= max_edges\n// https://noshi91.hatenablog.com/entry/2022/01/13/001217\n\
template <class Cost, class F>\nCost monge_shortest_path_with_specified_edges(int\
\ n, int min_edges, int max_edges,\n \
\ Cost max_abs_cost, F cost_callback) {\n\n assert(1 <= n);\n assert(0\
\ <= min_edges);\n assert(min_edges <= max_edges);\n assert(max_edges <=\
\ n - 1);\n\n monge_shortest_path<Cost> msp;\n\n auto eval = [&](Cost p)\
\ -> Cost {\n msp.solve(n, [&](int i, int j) { return cost_callback(i,\
\ j) - p; });\n return -msp.dist.back() - p * (p < 0 ? max_edges : min_edges);\n\
\ };\n\n Cost lo = -max_abs_cost * 3, hi = max_abs_cost * 3;\n\n while\
\ (lo + 1 < hi) {\n Cost p = (lo + hi) / 2, f = eval(p), df = eval(p +\
\ 1) - f;\n if (df == Cost()) {\n return -f;\n } else\
\ {\n (df < Cost() ? lo : hi) = p;\n }\n }\n\n Cost flo\
\ = eval(lo), fhi = eval(hi);\n\n return flo < fhi ? -flo : -fhi;\n}\n"
code: "#pragma once\n#include <cassert>\n#include <vector>\n\n// Shortest path of\
\ Monge-weighted graph\n// Variant of LARSCH Algorithm: https://noshi91.hatenablog.com/entry/2023/02/18/005856\n\
// Complexity: O(n log n)\n//\n// Given a directed graph with n vertices and weighted\
\ edges\n// (w(i, j) = cost_callback(i, j) (i < j)),\n// this class calculates\
\ the shortest path from vertex 0 to all other vertices.\ntemplate <class Cost>\
\ struct monge_shortest_path {\n std::vector<Cost> dist; // dist[i] = shortest\
\ distance from 0 to i\n std::vector<int> amin; // amin[i] = previous vertex\
\ of i in the shortest path\n\n template <class F> void _check(int i, int k,\
\ F cost_callback) {\n if (i <= k) return;\n if (Cost c = dist[k]\
\ + cost_callback(k, i); c < dist[i]) dist[i] = c, amin[i] = k;\n }\n\n \
\ template <class F> void _rec_solve(int l, int r, F cost_callback) {\n \
\ if (r - l == 1) return;\n\n const int m = (l + r) / 2;\n for\
\ (int k = amin[l]; k <= amin[r]; ++k) _check(m, k, cost_callback);\n\n \
\ _rec_solve(l, m, cost_callback);\n for (int k = l + 1; k <= m; ++k)\
\ _check(r, k, cost_callback);\n _rec_solve(m, r, cost_callback);\n \
\ }\n\n template <class F> Cost solve(int n, F cost_callback) {\n assert(n\
\ > 0);\n dist.resize(n);\n amin.assign(n, 0);\n\n dist[0]\
\ = Cost();\n for (int i = 1; i < n; ++i) dist[i] = cost_callback(0, i);\n\
\n _rec_solve(0, n - 1, cost_callback);\n\n return dist.back();\n\
\ }\n\n template <class F> int num_edges() const {\n int ret = 0;\n\
\ for (int c = (int)amin.size() - 1; c >= 0; c = amin[c]) ++ret;\n \
\ return ret;\n }\n};\n\n// Find shortest path length from 0 to n - 1 with\
\ k edges, min_edges <= k <= max_edges\n// https://noshi91.hatenablog.com/entry/2022/01/13/001217\n\
template <class Cost, class F>\nCost monge_shortest_path_with_specified_edges(int\
\ n, int min_edges, int max_edges,\n \
\ Cost max_abs_cost, F cost_callback) {\n\n assert(1 <= n);\n assert(0\
\ <= min_edges);\n assert(min_edges <= max_edges);\n assert(max_edges <=\
\ n - 1);\n\n monge_shortest_path<Cost> msp;\n\n auto eval = [&](Cost p)\
\ -> Cost {\n msp.solve(n, [&](int i, int j) { return cost_callback(i,\
\ j) - p; });\n return -msp.dist.back() - p * (p < 0 ? max_edges : min_edges);\n\
\ };\n\n Cost lo = -max_abs_cost * 3, hi = max_abs_cost * 3;\n\n while\
\ (lo + 1 < hi) {\n Cost p = (lo + hi) / 2, f = eval(p), df = eval(p +\
\ 1) - f;\n if (df == Cost()) {\n return -f;\n } else\
\ {\n (df < Cost() ? lo : hi) = p;\n }\n }\n\n Cost flo\
\ = eval(lo), fhi = eval(hi);\n\n return flo < fhi ? -flo : -fhi;\n}\n"
dependsOn: []
isVerificationFile: false
path: other_algorithms/monge_shortest_path.hpp
requiredBy: []
timestamp: '2024-10-06 15:03:01+09:00'
verificationStatus: LIBRARY_ALL_AC
verifiedWith:
- other_algorithms/test/monge_shortest_path.yuki705.test.cpp
documentation_of: other_algorithms/monge_shortest_path.hpp
layout: document
title: Shortest path of DAG with Monge weights
---

$n$ 頂点の DAG で辺重みが Monge となるようなものに対して最短路長を高速に求める. [1] で紹介されている簡易版 LARSCH Algorithm が実装されていて,計算量は $O(n \log n)$ .

また,辺数が `min_edges` 以上 `max_edges` 以下であるようなものに限った最短路長を高速に求めることも可能(計算量にさらに重み二分探索の $\log$ がつく).

## 使用方法

### 最短路長の計算

```cpp
auto f = [&](int s, int t) -> Cost {
//
};

monge_shortest_path<Cost> msp;
Cost ret = msp.solve(n, f);
```

### 辺の本数の下限・上限を指定した最短路長の計算

```cpp
auto f = [&](int s, int t) -> Cost {
//
};

int n; // 頂点数
int l, r; // 辺の本数が [l, r] の範囲に収まる最短路を見つけたい
Cost max_weight; // f() が返す値の絶対値の上界

Cost ret = monge_shortest_path_with_specified_edges(n, l, r, max_weight, f);
```

## 問題例

- [No.705 ゴミ拾い Hard - yukicoder](https://yukicoder.me/problems/no/705)
- [AtCoder Beginner Contest 218 H - Red and Blue Lamps](https://atcoder.jp/contests/abc218/tasks/abc218_h)
- [東京海上日動プログラミングコンテスト2024(AtCoder Beginner Contest 355) G - Baseball](https://atcoder.jp/contests/abc355/tasks/abc355_g)
- [東北大学プログラミングコンテスト 2022 K - Lebesgue Integral](https://atcoder.jp/contests/tupc2022/tasks/tupc2022_k)

## Links

- [1] [簡易版 LARSCH Algorithm - noshi91のメモ](https://noshi91.hatenablog.com/entry/2023/02/18/005856)
- [2] [Aliens DP における二分探索の色々 - noshi91のメモ](https://noshi91.hatenablog.com/entry/2023/11/20/052227#fn-c9578a2a)
12 changes: 8 additions & 4 deletions other_algorithms/smawk.hpp.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
data:
_extendedDependsOn: []
_extendedRequiredBy: []
_extendedVerifiedWith: []
_extendedVerifiedWith:
- icon: ':heavy_check_mark:'
path: other_algorithms/test/concave_max_plus_convolution.test.cpp
title: other_algorithms/test/concave_max_plus_convolution.test.cpp
_isVerificationFailed: false
_pathExtension: hpp
_verificationStatusIcon: ':warning:'
_verificationStatusIcon: ':heavy_check_mark:'
attributes:
links:
- http://web.cs.unlv.edu/larmore/Courses/CSC477/monge.pdf
Expand Down Expand Up @@ -98,8 +101,9 @@ data:
path: other_algorithms/smawk.hpp
requiredBy: []
timestamp: '2022-11-14 22:38:59+09:00'
verificationStatus: LIBRARY_NO_TESTS
verifiedWith: []
verificationStatus: LIBRARY_ALL_AC
verifiedWith:
- other_algorithms/test/concave_max_plus_convolution.test.cpp
documentation_of: other_algorithms/smawk.hpp
layout: document
title: Totally Monotone Matrix Searching (SMAWK)
Expand Down
89 changes: 89 additions & 0 deletions other_algorithms/test/concave_max_plus_convolution.test.cpp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
data:
_extendedDependsOn:
- icon: ':heavy_check_mark:'
path: other_algorithms/smawk.hpp
title: Totally Monotone Matrix Searching (SMAWK)
_extendedRequiredBy: []
_extendedVerifiedWith: []
_isVerificationFailed: false
_pathExtension: cpp
_verificationStatusIcon: ':heavy_check_mark:'
attributes:
'*NOT_SPECIAL_COMMENTS*': ''
PROBLEM: https://judge.yosupo.jp/problem/min_plus_convolution_convex_arbitrary
links:
- https://judge.yosupo.jp/problem/min_plus_convolution_convex_arbitrary
bundledCode: "#line 1 \"other_algorithms/test/concave_max_plus_convolution.test.cpp\"\
\n#define PROBLEM \"https://judge.yosupo.jp/problem/min_plus_convolution_convex_arbitrary\"\
\n\n#line 2 \"other_algorithms/smawk.hpp\"\n#include <cassert>\n#include <functional>\n\
#include <numeric>\n#include <unordered_map>\n#include <utility>\n#include <vector>\n\
\n// SMAWK: finding minima of totally monotone function f(i, j) (0 <= i < N, 0\
\ <= j < M) for each i\n// Constraints: every submatrix of f(i, j) is monotone.\n\
// Complexity: O(N + M)\n// Option: `Memorization`: Memorize all query results\
\ using hashmaps, effective when each query\n// requires heavy complexity Rererence:\n\
// https://topcoder-g-hatena-ne-jp.jag-icpc.org/spaghetti_source/20120923/1348327542.html\n\
// http://web.cs.unlv.edu/larmore/Courses/CSC477/monge.pdf\n// Verify: https://codeforces.com/contest/1423/submission/98368491\n\
template <typename T, bool Memorization> struct SMAWK {\n std::vector<std::pair<int,\
\ T>> minima;\n std::function<T(int, int)> oracle;\n std::vector<std::unordered_map<int,\
\ T>> memo;\n T _query(int i, int j) {\n if (Memorization)\n \
\ return memo[i].count(j) ? memo[i][j] : (memo[i][j] = oracle(i, j));\n \
\ else\n return oracle(i, j);\n }\n\n void _smawk_rec(const\
\ std::vector<int> &js, int ib, int ie, int id) {\n if (ib > ie) return;\n\
\ std::vector<int> js2;\n int i = ib;\n for (auto j : js)\
\ {\n while (!js2.empty() and _query(i, js2.back()) >= _query(i, j))\
\ js2.pop_back(), i -= id;\n if (int(js2.size()) != (ie - ib) / id)\
\ js2.push_back(j), i += id;\n }\n _smawk_rec(js2, ib + id, ie,\
\ id * 2);\n\n for (int i = ib, q = 0; i <= ie; i += id * 2) {\n \
\ int jt = (i + id <= ie ? minima[i + id].first : js.back());\n \
\ T fm = 0;\n bool init = true;\n for (; q < int(js.size());\
\ ++q) {\n T fq = _query(i, js[q]);\n if (init or\
\ fm > fq) fm = fq, minima[i] = std::make_pair(js[q], fq);\n init\
\ = false;\n if (js[q] == jt) break;\n }\n }\n\
\ }\n SMAWK(int N, int M, std::function<T(int i, int j)> oracle_) : minima(N),\
\ oracle(oracle_) {\n if (Memorization) memo.resize(N);\n std::vector<int>\
\ js(M);\n std::iota(js.begin(), js.end(), 0);\n _smawk_rec(js,\
\ 0, N - 1, 1);\n }\n};\n\n// Concave max-plus convolution\n// b must be concave\n\
// Complexity: O(n + m)\n// Verify: https://www.codechef.com/problems/MAXPREFFLIP\n\
template <class S, S INF>\nstd::vector<S> concave_max_plus_convolution(const std::vector<S>\
\ &a, const std::vector<S> &b) {\n const int n = a.size(), m = b.size();\n\n\
\ auto is_concave = [&](const std::vector<S> &u) -> bool {\n for (int\
\ i = 1; i + 1 < int(u.size()); ++i) {\n if (u[i - 1] + u[i + 1] >\
\ u[i] + u[i]) return false;\n }\n return true;\n };\n\n bool\
\ a_concave = is_concave(a), b_concave = is_concave(b);\n assert(a_concave\
\ or b_concave);\n if (!b_concave) return concave_max_plus_convolution<S, INF>(b,\
\ a);\n\n auto select = [&](int i, int j) -> S {\n int aidx = j, bidx\
\ = i - j;\n if (bidx < 0 or bidx >= m or aidx >= n) return INF;\n \
\ return -(a[aidx] + b[bidx]);\n };\n SMAWK<S, false> sm(n + m - 1, n,\
\ select);\n std::vector<S> ret;\n for (auto x : sm.minima) ret.push_back(-x.second);\n\
\ return ret;\n}\n#line 4 \"other_algorithms/test/concave_max_plus_convolution.test.cpp\"\
\n\n#include <iostream>\n#line 7 \"other_algorithms/test/concave_max_plus_convolution.test.cpp\"\
\nusing namespace std;\n\nint main() {\n cin.tie(nullptr);\n ios::sync_with_stdio(false);\n\
\n int N, M;\n cin >> N >> M;\n vector<int> A(N), B(M);\n for (auto\
\ &a : A) cin >> a, a = -a;\n for (auto &b : B) cin >> b, b = -b;\n\n auto\
\ ret = concave_max_plus_convolution<int, ((1 << 30) - 1) * 2>(B, A);\n\n for\
\ (int i = 0; i < N + M - 1; ++i) cout << -ret[i] << \" \\n\"[i + 1 == N + M -\
\ 1];\n}\n"
code: "#define PROBLEM \"https://judge.yosupo.jp/problem/min_plus_convolution_convex_arbitrary\"\
\n\n#include \"../smawk.hpp\"\n\n#include <iostream>\n#include <vector>\nusing\
\ namespace std;\n\nint main() {\n cin.tie(nullptr);\n ios::sync_with_stdio(false);\n\
\n int N, M;\n cin >> N >> M;\n vector<int> A(N), B(M);\n for (auto\
\ &a : A) cin >> a, a = -a;\n for (auto &b : B) cin >> b, b = -b;\n\n auto\
\ ret = concave_max_plus_convolution<int, ((1 << 30) - 1) * 2>(B, A);\n\n for\
\ (int i = 0; i < N + M - 1; ++i) cout << -ret[i] << \" \\n\"[i + 1 == N + M -\
\ 1];\n}\n"
dependsOn:
- other_algorithms/smawk.hpp
isVerificationFile: true
path: other_algorithms/test/concave_max_plus_convolution.test.cpp
requiredBy: []
timestamp: '2024-10-06 15:03:32+09:00'
verificationStatus: TEST_ACCEPTED
verifiedWith: []
documentation_of: other_algorithms/test/concave_max_plus_convolution.test.cpp
layout: document
redirect_from:
- /verify/other_algorithms/test/concave_max_plus_convolution.test.cpp
- /verify/other_algorithms/test/concave_max_plus_convolution.test.cpp.html
title: other_algorithms/test/concave_max_plus_convolution.test.cpp
---
Loading

0 comments on commit 0fc8c6c

Please sign in to comment.