This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub hitonanode/cplib-cpp
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" // DUMMY #include "../slope_trick.hpp" #include <cstdio> #include <random> #include <tuple> #include <utility> using namespace std; mt19937 mt(1010101); template <typename Int> pair<slope_trick<Int>, vector<Int>> gen_random_function(Int lo, Int hi) { slope_trick<Int> f; const Int dxmax = 10; int nquery = 100; const Int stupid_lo = lo - nquery * dxmax, stupid_hi = hi + nquery * dxmax; std::vector<Int> stupid_f(stupid_hi - stupid_lo + 1); for (int t = 0; t < nquery; t++) { int qtype = uniform_int_distribution<int>(0, 6)(mt); Int a = uniform_int_distribution<Int>(lo, hi)(mt); Int w = uniform_int_distribution<Int>(0, dxmax)(mt); if (qtype == 0) { Int b = uniform_int_distribution<Int>(-10000, 10000)(mt); f.add_const(b); for (Int x = stupid_lo; x <= stupid_hi; x++) stupid_f[x - stupid_lo] += b; } if (qtype == 1) { f.add_relu(a); for (Int x = stupid_lo; x <= stupid_hi; x++) stupid_f[x - stupid_lo] += max<Int>(x - a, 0); } if (qtype == 2) { f.add_irelu(a); for (Int x = stupid_lo; x <= stupid_hi; x++) stupid_f[x - stupid_lo] += max<Int>(a - x, 0); } if (qtype == 3) { f.add_abs(a); for (Int x = stupid_lo; x <= stupid_hi; x++) stupid_f[x - stupid_lo] += abs(x - a); } if (qtype == 4) { f.move_left_curve(w); for (Int x = stupid_lo; x <= stupid_hi; x++) { for (Int y = x + 1; y <= min(stupid_hi, x + w); y++) { stupid_f[x - stupid_lo] = min(stupid_f[x - stupid_lo], stupid_f[y - stupid_lo]); } } } if (qtype == 5) { f.move_right_curve(w); for (Int x = stupid_hi; x >= stupid_lo; x--) { for (Int y = x - 1; y >= max(stupid_lo, x - w); y--) { stupid_f[x - stupid_lo] = min(stupid_f[x - stupid_lo], stupid_f[y - stupid_lo]); } } } if (qtype == 6) { Int dx = uniform_int_distribution<Int>(-dxmax, dxmax)(mt); f.translate(dx); auto g = stupid_f; for (Int x = stupid_lo; x <= stupid_hi; x++) { Int y = x - dx; if (y >= stupid_lo and y <= stupid_hi) g[x - stupid_lo] = stupid_f[y - stupid_lo]; } stupid_f = g; } } vector<Int> fvals; for (Int x = lo; x <= hi; x++) { Int ret1 = stupid_f[x - stupid_lo]; auto g = f; Int ret2 = g.get_destructive(x); fvals.push_back(ret2); assert(ret1 == ret2); } return {f, fvals}; } template <typename Int> void merge_verify() { const Int lo = uniform_int_distribution<Int>(-10000, 10000)(mt); const Int hi = lo + 1000; slope_trick<Int> f, g; vector<Int> fval, gval; tie(f, fval) = gen_random_function(lo, hi); tie(g, gval) = gen_random_function(lo, hi); f.merge_destructive(g); for (Int x = lo; x <= hi; x++) { auto tmp = f; assert(tmp.get_destructive(x) == fval.at(x - lo) + gval.at(x - lo)); } } int main() { for (int t = 0; t < 1000; t++) { merge_verify<int>(); merge_verify<long long>(); } puts("Hello World"); }
#line 1 "other_algorithms/test/slope_trick_stress.test.cpp" #define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" // DUMMY #line 2 "other_algorithms/slope_trick.hpp" #include <algorithm> #include <cassert> #include <limits> #include <queue> #include <utility> // Slope trick: fast operations for convex piecewise-linear functions // Implementation idea: // - https://maspypy.com/slope-trick-1-%E8%A7%A3%E8%AA%AC%E7%B7%A8 // - https://ei1333.github.io/library/structure/others/slope-trick.cpp template <class T, T INF = std::numeric_limits<T>::max() / 2> class slope_trick { T min_f; T displacement_l, displacement_r; std::priority_queue<T, std::vector<T>, std::less<T>> L; std::priority_queue<T, std::vector<T>, std::greater<T>> R; void pushR(const T &a) { R.push(a - displacement_r); } T topR() const { return R.empty() ? INF : R.top() + displacement_r; } T popR() { auto ret = topR(); if (R.size()) R.pop(); return ret; } void pushL(const T &a) { L.push(a + displacement_l); } T topL() const { return L.empty() ? -INF : L.top() - displacement_l; } T popL() { auto ret = topL(); if (L.size()) L.pop(); return ret; } public: // Initialize, f(x) = 0 everywhere // Complexity: O(1) slope_trick() : min_f(0), displacement_l(0), displacement_r(0) { static_assert(INF > 0, "INF must be greater than 0"); } inline int sizeL() const noexcept { return L.size(); } inline int sizeR() const noexcept { return R.size(); } // argmin f(x), min f(x) // Complexity: O(1) using Q = struct { T min, lo, hi; }; Q get_min() const { return {min_f, topL(), topR()}; } // f(x) += b // Complexity: O(1) slope_trick &add_const(const T &b) { return min_f += b, *this; } // f(x) += max(x - a, 0) _/ // Complexity: O(log n) slope_trick &add_relu(const T &a) { return min_f += std::max(T(0), topL() - a), pushL(a), pushR(popL()), *this; } // f(x) += max(a - x, 0) \_ // Complexity: O(log n) slope_trick &add_irelu(const T &a) { return min_f += std::max(T(0), a - topR()), pushR(a), pushL(popR()), *this; } // f(x) += |x - a| \/ // Complexity: O(log n) slope_trick &add_abs(const T &a) { return add_relu(a).add_irelu(a); } // f(x) <- min_{0 <= y <= w} f(x + y) .\ -> \_ // Complexity: O(1) slope_trick &move_left_curve(const T &w) { return assert(w >= 0), displacement_l += w, *this; } // f(x) <- min_{0 <= y <= w} f(x - y) /. -> _/ // Complexity: O(1) slope_trick &move_right_curve(const T &w) { return assert(w >= 0), displacement_r += w, *this; } // f(x) <- f(x - dx) \/. -> .\/ // Complexity: O(1) slope_trick &translate(const T &dx) { return displacement_l -= dx, displacement_r += dx, *this; } // return f(x), f destructive T get_destructive(const T &x) { T ret = get_min().min; while (L.size()) ret += std::max(T(0), popL() - x); while (R.size()) ret += std::max(T(0), x - popR()); return ret; } // f(x) += g(x), g destructive slope_trick &merge_destructive(slope_trick<T, INF> &g) { if (sizeL() + sizeR() > g.sizeL() + g.sizeR()) { std::swap(min_f, g.min_f); std::swap(displacement_l, g.displacement_l); std::swap(displacement_r, g.displacement_r); std::swap(L, g.L); std::swap(R, g.R); } min_f += g.get_min().min; while (g.L.size()) add_irelu(g.popL()); while (g.R.size()) add_relu(g.popR()); return *this; } }; #line 3 "other_algorithms/test/slope_trick_stress.test.cpp" #include <cstdio> #include <random> #include <tuple> #line 7 "other_algorithms/test/slope_trick_stress.test.cpp" using namespace std; mt19937 mt(1010101); template <typename Int> pair<slope_trick<Int>, vector<Int>> gen_random_function(Int lo, Int hi) { slope_trick<Int> f; const Int dxmax = 10; int nquery = 100; const Int stupid_lo = lo - nquery * dxmax, stupid_hi = hi + nquery * dxmax; std::vector<Int> stupid_f(stupid_hi - stupid_lo + 1); for (int t = 0; t < nquery; t++) { int qtype = uniform_int_distribution<int>(0, 6)(mt); Int a = uniform_int_distribution<Int>(lo, hi)(mt); Int w = uniform_int_distribution<Int>(0, dxmax)(mt); if (qtype == 0) { Int b = uniform_int_distribution<Int>(-10000, 10000)(mt); f.add_const(b); for (Int x = stupid_lo; x <= stupid_hi; x++) stupid_f[x - stupid_lo] += b; } if (qtype == 1) { f.add_relu(a); for (Int x = stupid_lo; x <= stupid_hi; x++) stupid_f[x - stupid_lo] += max<Int>(x - a, 0); } if (qtype == 2) { f.add_irelu(a); for (Int x = stupid_lo; x <= stupid_hi; x++) stupid_f[x - stupid_lo] += max<Int>(a - x, 0); } if (qtype == 3) { f.add_abs(a); for (Int x = stupid_lo; x <= stupid_hi; x++) stupid_f[x - stupid_lo] += abs(x - a); } if (qtype == 4) { f.move_left_curve(w); for (Int x = stupid_lo; x <= stupid_hi; x++) { for (Int y = x + 1; y <= min(stupid_hi, x + w); y++) { stupid_f[x - stupid_lo] = min(stupid_f[x - stupid_lo], stupid_f[y - stupid_lo]); } } } if (qtype == 5) { f.move_right_curve(w); for (Int x = stupid_hi; x >= stupid_lo; x--) { for (Int y = x - 1; y >= max(stupid_lo, x - w); y--) { stupid_f[x - stupid_lo] = min(stupid_f[x - stupid_lo], stupid_f[y - stupid_lo]); } } } if (qtype == 6) { Int dx = uniform_int_distribution<Int>(-dxmax, dxmax)(mt); f.translate(dx); auto g = stupid_f; for (Int x = stupid_lo; x <= stupid_hi; x++) { Int y = x - dx; if (y >= stupid_lo and y <= stupid_hi) g[x - stupid_lo] = stupid_f[y - stupid_lo]; } stupid_f = g; } } vector<Int> fvals; for (Int x = lo; x <= hi; x++) { Int ret1 = stupid_f[x - stupid_lo]; auto g = f; Int ret2 = g.get_destructive(x); fvals.push_back(ret2); assert(ret1 == ret2); } return {f, fvals}; } template <typename Int> void merge_verify() { const Int lo = uniform_int_distribution<Int>(-10000, 10000)(mt); const Int hi = lo + 1000; slope_trick<Int> f, g; vector<Int> fval, gval; tie(f, fval) = gen_random_function(lo, hi); tie(g, gval) = gen_random_function(lo, hi); f.merge_destructive(g); for (Int x = lo; x <= hi; x++) { auto tmp = f; assert(tmp.get_destructive(x) == fval.at(x - lo) + gval.at(x - lo)); } } int main() { for (int t = 0; t < 1000; t++) { merge_verify<int>(); merge_verify<long long>(); } puts("Hello World"); }