This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub kmyk/competitive-programming-library
class convex_hull_trick_with_monotonicity { typedef pair<ll, ll> line_t; deque<line_t> lines; ll inc_x, dec_x; // only for assertions public: convex_hull_trick_with_monotonicity() { inc_x = LLONG_MIN; dec_x = LLONG_MAX; } void add_line_increasing(ll a, ll b) { assert (lines.empty() or lines.back().first <= a); // weakly monotonically increasing while (lines.size() >= 2 and not is_required(lines[lines.size() - 2], lines.back(), { a, b })) { lines.pop_back(); } lines.emplace_back(a, b); } void add_line_decreasing(ll a, ll b) { assert (lines.empty() or a <= lines.front().first); // weakly monotonically decreasing while (lines.size() >= 2 and not is_required({ a, b }, lines.front(), lines[1])) { lines.pop_front(); } lines.emplace_front(a, b); } ll get_max_increasing(ll x) { assert (inc_x <= x); // weakly monotonically increasing inc_x = x; assert (not lines.empty()); while (lines.size() >= 2 and get_value(0, x) <= get_value(1, x)) { lines.pop_front(); } return get_value(0, x); } ll get_max_decreasing(ll x) { assert (x <= dec_x); // weakly monotonically decreasing dec_x = x; assert (not lines.empty()); while (lines.size() >= 2 and get_value(-2, x) >= get_value(-1, x)) { lines.pop_back(); } return get_value(-1, x); } private: bool is_required(line_t f1, line_t f2, line_t f3) const { return (f3.first - f1.first) * (f1.second - f2.second) < (f2.first - f1.first) * (f1.second - f3.second); } ll get_value(int i, ll x) const { if (i < 0) i += lines.size(); ll a, b; tie(a, b) = lines[i]; return a * x + b; } }; struct inverted_convex_hull_trick_with_monotonicity { convex_hull_trick_with_monotonicity data; void add_line_increasing(ll a, ll b) { data.add_line_decreasing(- a, - b); } void add_line_decreasing(ll a, ll b) { data.add_line_increasing(- a, - b); } ll get_max_increasing(ll x) { return - data.get_max_increasing(x); } ll get_max_decreasing(ll x) { return - data.get_max_decreasing(x); } }; unittest() { default_random_engine gen; REP (iteration, 10000) { bool inc_f = bernoulli_distribution(0.5)(gen); bool inc_x = bernoulli_distribution(0.5)(gen); vector<pair<int, int> > lines; REP (i, 30) { int a = uniform_int_distribution<int>(- 30, 30)(gen); int b = uniform_int_distribution<int>(- 30, 30)(gen); lines.emplace_back(a, b); } sort(ALL(lines)); if (inc_f) { // nop } else { reverse(ALL(lines)); } convex_hull_trick_with_monotonicity cht; int x = uniform_int_distribution<int>(- 100, 100)(gen); REP (i, lines.size()) { int y = INT_MIN; REP (j, i + 1) { int a, b; tie(a, b) = lines[j]; chmax(y, a * x + b); } int a, b; tie(a, b) = lines[i]; if (inc_f) { cht.add_line_increasing(a, b); } else { cht.add_line_decreasing(a, b); } if (inc_x) { assert (cht.get_max_increasing(x) == y); x += uniform_int_distribution<int>(0, 5)(gen); } else { assert (cht.get_max_decreasing(x) == y); x -= uniform_int_distribution<int>(0, 5)(gen); } } } }
#line 1 "old/convex-hull-trick-with-monotonicity.inc.cpp" class convex_hull_trick_with_monotonicity { typedef pair<ll, ll> line_t; deque<line_t> lines; ll inc_x, dec_x; // only for assertions public: convex_hull_trick_with_monotonicity() { inc_x = LLONG_MIN; dec_x = LLONG_MAX; } void add_line_increasing(ll a, ll b) { assert (lines.empty() or lines.back().first <= a); // weakly monotonically increasing while (lines.size() >= 2 and not is_required(lines[lines.size() - 2], lines.back(), { a, b })) { lines.pop_back(); } lines.emplace_back(a, b); } void add_line_decreasing(ll a, ll b) { assert (lines.empty() or a <= lines.front().first); // weakly monotonically decreasing while (lines.size() >= 2 and not is_required({ a, b }, lines.front(), lines[1])) { lines.pop_front(); } lines.emplace_front(a, b); } ll get_max_increasing(ll x) { assert (inc_x <= x); // weakly monotonically increasing inc_x = x; assert (not lines.empty()); while (lines.size() >= 2 and get_value(0, x) <= get_value(1, x)) { lines.pop_front(); } return get_value(0, x); } ll get_max_decreasing(ll x) { assert (x <= dec_x); // weakly monotonically decreasing dec_x = x; assert (not lines.empty()); while (lines.size() >= 2 and get_value(-2, x) >= get_value(-1, x)) { lines.pop_back(); } return get_value(-1, x); } private: bool is_required(line_t f1, line_t f2, line_t f3) const { return (f3.first - f1.first) * (f1.second - f2.second) < (f2.first - f1.first) * (f1.second - f3.second); } ll get_value(int i, ll x) const { if (i < 0) i += lines.size(); ll a, b; tie(a, b) = lines[i]; return a * x + b; } }; struct inverted_convex_hull_trick_with_monotonicity { convex_hull_trick_with_monotonicity data; void add_line_increasing(ll a, ll b) { data.add_line_decreasing(- a, - b); } void add_line_decreasing(ll a, ll b) { data.add_line_increasing(- a, - b); } ll get_max_increasing(ll x) { return - data.get_max_increasing(x); } ll get_max_decreasing(ll x) { return - data.get_max_decreasing(x); } }; unittest() { default_random_engine gen; REP (iteration, 10000) { bool inc_f = bernoulli_distribution(0.5)(gen); bool inc_x = bernoulli_distribution(0.5)(gen); vector<pair<int, int> > lines; REP (i, 30) { int a = uniform_int_distribution<int>(- 30, 30)(gen); int b = uniform_int_distribution<int>(- 30, 30)(gen); lines.emplace_back(a, b); } sort(ALL(lines)); if (inc_f) { // nop } else { reverse(ALL(lines)); } convex_hull_trick_with_monotonicity cht; int x = uniform_int_distribution<int>(- 100, 100)(gen); REP (i, lines.size()) { int y = INT_MIN; REP (j, i + 1) { int a, b; tie(a, b) = lines[j]; chmax(y, a * x + b); } int a, b; tie(a, b) = lines[i]; if (inc_f) { cht.add_line_increasing(a, b); } else { cht.add_line_decreasing(a, b); } if (inc_x) { assert (cht.get_max_increasing(x) == y); x += uniform_int_distribution<int>(0, 5)(gen); } else { assert (cht.get_max_decreasing(x) == y); x -= uniform_int_distribution<int>(0, 5)(gen); } } } }