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", 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/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/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/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) { 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(); + } +} 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