From e75dba676022369d22d40dbf90243d516a059eef Mon Sep 17 00:00:00 2001 From: hitonanode <32937551+hitonanode@users.noreply.github.com> Date: Mon, 20 Sep 2021 19:53:17 +0900 Subject: [PATCH 1/3] Rename methods of Li-Chao tree --- convex_hull_trick/li_chao_tree.hpp | 6 +++--- convex_hull_trick/li_chao_tree.md | 2 +- convex_hull_trick/test/li_chao_tree.test.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/convex_hull_trick/li_chao_tree.hpp b/convex_hull_trick/li_chao_tree.hpp index e116dbbe..19a20709 100644 --- a/convex_hull_trick/li_chao_tree.hpp +++ b/convex_hull_trick/li_chao_tree.hpp @@ -6,7 +6,7 @@ // Li-Chao tree // init() : set x's where we will execute get(x) queries -// add_segment(l, r, a, b): update by ax + b in [l, r) +// insert_segment(l, r, a, b): update by ax + b in [l, r) // get(x): get min template struct li_chao_tree { int _n, _head; @@ -78,12 +78,12 @@ template struct li_chao_tree { } } - void add_line(T a, T b, int idx = -1) { + void insert_line(T a, T b, int idx = -1) { il = 0, ir = _n; if (il >= ir) return; _rec(1, 0, _head, _Line{a, b, idx, true}); } - void add_segment(T xl, T xr, T a, T b, int idx = -1) { + void insert_segment(T xl, T xr, T a, T b, int idx = -1) { il = std::lower_bound(xs.begin(), xs.end(), xl) - xs.begin(); ir = std::lower_bound(xs.begin(), xs.end(), xr) - xs.begin(); if (il >= ir) return; diff --git a/convex_hull_trick/li_chao_tree.md b/convex_hull_trick/li_chao_tree.md index fad0a37b..b156ed37 100644 --- a/convex_hull_trick/li_chao_tree.md +++ b/convex_hull_trick/li_chao_tree.md @@ -13,7 +13,7 @@ vector xs; li_chao_tree tree; tree.init(xs); // xs が昇順である必要はない -tree.add_segment(l, r, a, b, 0); // chmin by ax + b in [l, r) +tree.insert_segment(l, r, a, b, 0); // chmin by ax + b in [l, r) ret = tree.get(x); cout << ret.minval << endl; diff --git a/convex_hull_trick/test/li_chao_tree.test.cpp b/convex_hull_trick/test/li_chao_tree.test.cpp index f58eb96e..b16ae291 100644 --- a/convex_hull_trick/test/li_chao_tree.test.cpp +++ b/convex_hull_trick/test/li_chao_tree.test.cpp @@ -36,7 +36,7 @@ int main() { for (auto q : qs) { tie(tp, l, r, a, b) = q; - if (tp == 0) tree.add_segment(l, r, a, b, 0); + if (tp == 0) tree.insert_segment(l, r, a, b, 0); if (tp == 1) { auto ret = tree.get(l); if (ret.is_valid) { From 8a2a1ac076750dfe8f8bd84caf5c24eccff3378c Mon Sep 17 00:00:00 2001 From: hitonanode <32937551+hitonanode@users.noreply.github.com> Date: Mon, 20 Sep 2021 20:03:18 +0900 Subject: [PATCH 2/3] Refactor & add test for monotone-insert-get CHT --- convex_hull_trick/add-get-monotone_cht.hpp | 69 --------------- convex_hull_trick/monotone-insert-get-cht.md | 17 ++++ convex_hull_trick/monotone-insert-get_cht.hpp | 85 +++++++++++++++++++ .../test/monotone-insert-get_cht.test.cpp | 27 ++++++ 4 files changed, 129 insertions(+), 69 deletions(-) delete mode 100644 convex_hull_trick/add-get-monotone_cht.hpp create mode 100644 convex_hull_trick/monotone-insert-get-cht.md create mode 100644 convex_hull_trick/monotone-insert-get_cht.hpp create mode 100644 convex_hull_trick/test/monotone-insert-get_cht.test.cpp diff --git a/convex_hull_trick/add-get-monotone_cht.hpp b/convex_hull_trick/add-get-monotone_cht.hpp deleted file mode 100644 index f27d6067..00000000 --- a/convex_hull_trick/add-get-monotone_cht.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once -#include -#include -#include - -// CUT begin -// Convex Hull Trick for monotone increasing queries, monotone decreasing slopes -// Each operation is amortized O(1) -// - is_minimizer: if true, calculates min. Otherwise, calculates max. -// - add_line(a, b): Add `y = ax + b`, a must be monotone decreasing (if is_minimizer == true) / increasing (otherwise) -// - add_convex_parabola(c, a, b): Add `y = c(x - a)^2 + b`, c is constant, a is monotone increasing (if is_minimizer == true) / decreasing (otherwise) -// - get(x): Calculate min/max. value of `y = ax + b`'s at point x, x must be monotone increasing FOR BOTH CASES. -// - parabola_get(c, x): Caclculate min/max. value of `y = c(x - a)^2 + b`'s, x must be monotone increasing FOR BOTH CASES. -// - If you need random access, change `std::list` to `std::deque` -// Verified: -template -struct MonotoneConvexHullTrick : std::list> // (a, b) means `y = ax + b` -{ - MonotoneConvexHullTrick() = default; - void add_line(T_CHT a, T_CHT b) { // Add y = ax + b - if (!is_minimizer) a = -a, b = -b; - assert(this->empty() or this->back().first >= a); - while (this->size() > 1u) { - if (this->back().first == a) { - if (this->back().second <= b) { - return; - } else { - this->pop_back(); - continue; - } - } - auto ill = std::prev(this->end(), 2); - auto l = (T_MP)(this->back().second - ill->second) * (this->back().first - a); // Overflow might occur here. - auto r = (T_MP)(b - this->back().second) * (ill->first - this->back().first); - if (l < r) break; - this->pop_back(); - } - this->emplace_back(a, b); - } - T_CHT get(T_CHT x) { - while (this->size() > 1u and - this->begin()->first * x + this->begin()->second >= (++this->begin())->first * x + (++this->begin())->second) - this->pop_front(); - return (this->empty() ? INF : this->begin()->first * x + this->begin()->second) * (is_minimizer ? 1 : -1); - } - void add_convex_parabola(T_CHT c, T_CHT a, T_CHT b) { add_line(c * a * (-2), c * a * a + b); } - T_CHT parabola_get(T_CHT c, T_CHT x) { return get(x) + c * x * x; } - - static MonotoneConvexHullTrick merge(const MonotoneConvexHullTrick &cht1, const MonotoneConvexHullTrick &cht2) { - MonotoneConvexHullTrick ret; - auto i1 = cht1.begin(), i2 = cht2.begin(); - static const T_CHT sgn = is_minimizer ? 1 : -1; - T_CHT a = 0, b = 0; - while (i1 != cht1.end() and i2 != cht2.end()) { - if (i1->first == i2->first) { - a = i1->first, b = std::min(i1->second, i2->second); - i1++, i2++; - } else if (i1->first > i2->first) { - a = i1->first, b = i1->second, i1++; - } else { - a = i2->first, b = i2->second, i2++; - } - ret.add_line(a * sgn, b * sgn); - } - while (i1 != cht1.end()) ret.add_line(i1->first * sgn, i1->second * sgn), i1++; - while (i2 != cht2.end()) ret.add_line(i2->first * sgn, i2->second * sgn), i2++; - return ret; - } -}; diff --git a/convex_hull_trick/monotone-insert-get-cht.md b/convex_hull_trick/monotone-insert-get-cht.md new file mode 100644 index 00000000..b0d6ce0e --- /dev/null +++ b/convex_hull_trick/monotone-insert-get-cht.md @@ -0,0 +1,17 @@ +--- +title: Convex hull trick (monotone insert, monotone get) +documentation_of: ./monotone-insert-get_cht.hpp +--- + +各クエリが償却 $O(1)$. + +- `insert_line(T a, T b)` 直線追加クエリ.追加される直線 $y = ax + b$ について,$a$ の値が単調非増加(最小値取得) / 単調非減少(最大値取得). +- `get(T x)` 最小値・最大値取得クエリ.取得する $x$ 座標は単調非減少. + +- `insert_convex_parabola(T c, T a, T b)` 放物線 $y = c(x - a)^2 + b$ の追加クエリ.$c$ の値は全クエリで共通でなければならない.最小値取得の場合,$ca$ の値が単調増加でなければならない. +- `parabola_get(T c, T x)` 放物線たちの最小値・最大値取得クエリ.取得する $x$ 座標は単調非減少. +- `merge(CHT cht1, CHT cht2)` 二つの CHT をマージする.計算量は $O(\mathrm{size}(\mathrm{cht1}) + \mathrm{size}(\mathrm{cht2}))$. + +## 問題例 + +- [No.952 危険な火薬庫 - yukicoder](https://yukicoder.me/problems/no/952) diff --git a/convex_hull_trick/monotone-insert-get_cht.hpp b/convex_hull_trick/monotone-insert-get_cht.hpp new file mode 100644 index 00000000..ba8f5f9f --- /dev/null +++ b/convex_hull_trick/monotone-insert-get_cht.hpp @@ -0,0 +1,85 @@ +#pragma once +#include +#include +#include + +// CUT begin +// Convex Hull Trick for monotone increasing queries, monotone decreasing slopes +// Each operation is amortized O(1) +// - is_minimizer: if true, calculates min. Otherwise, calculates max. +// - insert_line(a, b): Insert `y = ax + b`, +// a must be monotone decreasing (if is_minimizer == true) / increasing (otherwise) +// - add_convex_parabola(c, a, b): Add `y = c(x - a)^2 + b`, c is constant, a is monotone +// increasing (if is_minimizer == true) / decreasing (otherwise) +// - get(x): Calculate min/max. value of `y = ax + b`'s at point x, x must be monotone +// increasing FOR BOTH CASES. +// - parabola_get(c, x): Caclculate min/max. value of `y = c(x - a)^2 + b`'s, x must be monotone +// increasing FOR BOTH CASES. +// - If you need random access, change `std::list` to `std::deque` +// Verified: https://yukicoder.me/submissions/409156 +template +class MonotoneConvexHullTrick : std::list> { + // (a, b) means `y = ax + b` + T_MP _eval(typename std::list>::const_iterator itr, T x) { + return T_MP(itr->first) * x + itr->second; + } + +public: + MonotoneConvexHullTrick() { static_assert(INF > 0, "INF must be positive."); } + void insert_line(T a, T b) { // Add y = ax + b + if (!is_minimizer) a = -a, b = -b; + assert(this->empty() or this->back().first >= a); + while (this->size() > 1u) { + if (this->back().first == a) { + if (this->back().second <= b) return; + this->pop_back(); + continue; + } + auto ill = std::prev(this->end(), 2); + auto l = (T_MP)(this->back().second - ill->second) * (this->back().first - a); + auto r = (T_MP)(b - this->back().second) * (ill->first - this->back().first); + if (l < r) break; + this->pop_back(); + } + this->emplace_back(a, b); + } + + struct Ret { + T line_a, line_b; + bool is_valid; + T_MP val; + }; + Ret get(T x) { + if (this->empty()) return {0, 0, false, is_minimizer ? INF : -INF}; + while (this->size() > 1 and _eval(this->begin(), x) >= _eval(std::next(this->begin()), x)) { + this->pop_front(); + } + T_MP val = _eval(this->begin(), x) * (is_minimizer ? 1 : -1); + return {(is_minimizer ? 1 : -1) * this->begin()->first, + (is_minimizer ? 1 : -1) * this->begin()->second, true, val}; + } + void insert_convex_parabola(T c, T a, T b) { insert_line(c * a * (-2), c * a * a + b); } + T_MP parabola_get(T c, T x) { return get(x).val + c * x * x; } + + static MonotoneConvexHullTrick + merge(const MonotoneConvexHullTrick &cht1, const MonotoneConvexHullTrick &cht2) { + MonotoneConvexHullTrick ret; + auto i1 = cht1.begin(), i2 = cht2.begin(); + static const T sgn = is_minimizer ? 1 : -1; + T a = 0, b = 0; + while (i1 != cht1.end() and i2 != cht2.end()) { + if (i1->first == i2->first) { + a = i1->first, b = std::min(i1->second, i2->second); + ++i1, ++i2; + } else if (i1->first > i2->first) { + a = i1->first, b = i1->second, ++i1; + } else { + a = i2->first, b = i2->second, ++i2; + } + ret.insert_line(a * sgn, b * sgn); + } + while (i1 != cht1.end()) ret.insert_line(i1->first * sgn, i1->second * sgn), ++i1; + while (i2 != cht2.end()) ret.insert_line(i2->first * sgn, i2->second * sgn), ++i2; + return ret; + } +}; diff --git a/convex_hull_trick/test/monotone-insert-get_cht.test.cpp b/convex_hull_trick/test/monotone-insert-get_cht.test.cpp new file mode 100644 index 00000000..c78cf154 --- /dev/null +++ b/convex_hull_trick/test/monotone-insert-get_cht.test.cpp @@ -0,0 +1,27 @@ +#define PROBLEM "https://yukicoder.me/problems/no/952" +#include "../monotone-insert-get_cht.hpp" +#include +#include +using namespace std; + +int main() { + int N; + cin >> N; + vector A(N); + for (auto &x : A) cin >> x; + vector> cht(N + 1); + int x = 0; + cht[0].insert_convex_parabola(1, x, 0); + for (int i = 0; i < N; ++i) { + for (int d = i; d >= 0; --d) { + long long v = cht[d].parabola_get(1, x); + cht[d + 1].insert_convex_parabola(1, x + A[i], v); + } + x += A[i]; + } + cht.pop_back(); + while (!cht.empty()) { + cout << (long long)cht.back().parabola_get(1, x) << '\n'; + cht.pop_back(); + } +} From 6989d763e5849b2f8b2bb0d9ceec9b7cb95d001d Mon Sep 17 00:00:00 2001 From: GitHub Date: Mon, 20 Sep 2021 11:06:45 +0000 Subject: [PATCH 3/3] [auto-verifier] verify commit 8a2a1ac076750dfe8f8bd84caf5c24eccff3378c --- .verify-helper/timestamps.remote.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.verify-helper/timestamps.remote.json b/.verify-helper/timestamps.remote.json index e3dcf058..2d3a3bf9 100644 --- a/.verify-helper/timestamps.remote.json +++ b/.verify-helper/timestamps.remote.json @@ -21,7 +21,8 @@ "combinatorial_opt/test/simplex.multiprecision.test.cpp": "2021-02-28 16:53:36 +0900", "combinatorial_opt/test/simplex.shortestpath.test.cpp": "2021-02-28 16:53:36 +0900", "convex_hull_trick/test/convex_hull_trick.test.cpp": "2020-11-18 20:33:55 +0900", -"convex_hull_trick/test/li_chao_tree.test.cpp": "2021-09-16 00:36:41 +0900", +"convex_hull_trick/test/li_chao_tree.test.cpp": "2021-09-20 19:53:17 +0900", +"convex_hull_trick/test/monotone-insert-get_cht.test.cpp": "2021-09-20 20:03:18 +0900", "convolution/test/bitwise_and_conv.test.cpp": "2021-06-06 14:54:00 +0900", "convolution/test/bitwise_xor_conv.test.cpp": "2021-06-06 14:54:00 +0900", "convolution/test/hadamard_xor.test.cpp": "2020-12-20 04:05:21 +0900", pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy