#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include template void unique_inplace(std::vector& A) { if (!std::is_sorted(A.begin(), A.end())) { std::sort(A.begin(), A.end()); } A.erase(std::unique(A.begin(), A.end()), A.end()); } struct IOSetup { IOSetup() { std::cin.tie(nullptr); std::ios::sync_with_stdio(false); std::cout << std::fixed << std::setprecision(15); std::cerr << std::fixed << std::setprecision(8); } }; IOSetup iosetup; using int128_t = __int128; using uint128_t = unsigned __int128; template constexpr auto rep_iota_impl(T start, T stop) noexcept { return std::views::iota(start, (start < stop ? stop : start)); } template constexpr auto rep_impl(auto start, auto stop) noexcept { return rep_iota_impl(start, stop); } template constexpr auto rep_impl(auto stop) noexcept { return rep_iota_impl(0, stop); } template inline void read(Ts&... ts) { (std::cin >> ... >> ts); } template inline bool chmax(T& a, U b) { if (a < b) { a = b; return true; } return false; } template inline bool chmin(T& a, U b) { if (a > b) { a = b; return true; } return false; } using std::vector; template struct MAdd { using ll = int64_t; using T = X; static constexpr T op(const T& x, const T& y) noexcept { return x + y; } static constexpr T inverse(const T& x) noexcept { return -x; } static constexpr T power(const T& x, ll n) noexcept { return T{x} * n; } static constexpr T unit() noexcept { return T{}; } static constexpr bool is_unit(const T& x) noexcept { return x == T{}; } static constexpr bool commutative = 1; static constexpr bool invertible = 1; }; template void put(const T& t) { std::cout << t; } template void print(const Ts&... ts) { put(ts...); std::cout << "\n"; } using std::cin; using std::cout; using std::map; using std::pair; using std::set; using std::string; using std::tuple; using std::vector; using ll = int64_t; template struct DynamicLazySegTree { public: using ll = int64_t; using MX = MX_; using MA = MA_; using X = typename MX::T; using A = typename MA::T; using value_type = typename MX::T; static_assert(std::is_invocable_v); struct Node; using Tree = Node*; struct Node { X val; A lazy; Tree left, right; Node() : val(MX::unit()), lazy(MA::unit()), left(nullptr), right(nullptr) {} }; auto _new(ll nL, ll nR) { auto t = new Node(); t->val = default_factory(nL, nR); return t; } inline void _del(Tree t) { delete t; } void _delete_subtree(Tree t) { if (!t) return; _delete_subtree(t->left); _delete_subtree(t->right); _del(t); } void clear() { _delete_subtree(root); root = nullptr; } Tree root; const ll maxlen; DynamicLazySegTree() = default; explicit DynamicLazySegTree(ll maxlen_) : root(_new(0, maxlen_)), maxlen(maxlen_) { assert(maxlen_ >= 0); } private: void apply_subtree(Tree t, const A& a, const ll nL, const ll nR) const { assert(nL < nR); t->val = operate(t->val, a, nR - nL); t->lazy = MA::op(t->lazy, a); } void push_lazy(Tree t, ll nL, ll nR) { assert(nR - nL >= 2); if (nR - nL == 1) return; assert(t); if (t->lazy == MA::unit()) return; ll m = std::midpoint(nL, nR); if (!t->left) t->left = _new(nL, m); if (!t->right) t->right = _new(m, nR); apply_subtree(t->left, t->lazy, nL, m); apply_subtree(t->right, t->lazy, m, nR); t->lazy = MA::unit(); } void update(Tree t, ll nL, ll nR) { assert(t); assert(nR - nL >= 2); if (nR - nL == 1) return; ll m = std::midpoint(nL, nR); X vL = t->left ? t->left->val : default_factory(nL, m); X vR = t->right ? t->right->val : default_factory(m, nR); t->val = MX::op(vL, vR); } public: X fold(ll l, ll r) { return _fold(l, r, MA::unit(), root, 0, maxlen); } X fold_all() { return fold(0, maxlen); } X _fold(ll l, ll r, const A lazy, Tree t, const ll nL, const ll nR) { chmax(l, nL); chmin(r, nR); if (not(l < r)) return MX::unit(); if (!t) { return operate(default_factory(l, r), lazy, r - l); } if (l == nL && r == nR) { return operate(t->val, lazy, r - l); } ll m = std::midpoint(nL, nR); A nlazy = MA::op(t->lazy, lazy); X vL = _fold(l, r, nlazy, t->left, nL, m); X vR = _fold(l, r, nlazy, t->right, m, nR); return MX::op(vL, vR); } void apply(const ll l, const ll r, const A& a) { _apply(l, r, a, root, 0, maxlen); } Tree _apply(ll l, ll r, const A a, Tree t, const ll nL, const ll nR) { if (a == MA::unit()) return t; if (!t) t = _new(nL, nR); chmax(l, nL); chmin(r, nR); if (not(l < r)) return t; if (l == nL && r == nR) { apply_subtree(t, a, nL, nR); return t; } push_lazy(t, nL, nR); ll m = std::midpoint(nL, nR); t->left = _apply(l, r, a, t->left, nL, m); t->right = _apply(l, r, a, t->right, m, nR); update(t, nL, nR); return t; } void set(const ll i, const X& x) { assert(0 <= i && i < maxlen); root = _set(i, x, root, 0, maxlen); } Tree _set(const ll i, const X& x, Tree t, const ll nL, const ll nR) { if (nR - nL == 1) { t->val = x; t->lazy = MA::unit(); return t; } push_lazy(t, nL, nR); ll m = std::midpoint(nL, nR); if (!t->left) t->left = _new(nL, m); if (!t->right) t->right = _new(m, nR); if (i < m) { t->left = _set(i, x, t->left, nL, m); } else { t->right = _set(i, x, t->right, m, nR); } update(t, nL, nR); return t; } X operator[](ll k) const { return fold(k, k + 1); } X get(ll k) const { return fold(k, k + 1); } }; constexpr int64_t INF = 23e17; template struct MMax { using T = X; static constexpr T op(T x, T y) { return (x < y) ? y : x; } static constexpr T unit() { return -INF; } static constexpr bool is_unit(const T& x) { return x == -INF; } static constexpr bool commutative = true; static constexpr bool idempotent = true; }; ll operate(ll M, ll a, [[maybe_unused]] ll sz) { return M + a; } ll default_factory(ll l, ll r) { return 0; } struct Point { ll x, y, v; }; ll resolve(ll N, ll P, ll Q, vector XYV) { ll minY = INF; for (const auto i : rep_impl((N))) { auto [x, y, v] = XYV[i]; chmin(minY, y); } for (const auto i : rep_impl((N))) { auto [x, y, v] = XYV[i]; XYV[i] = {x, y - minY + (Q - 1), v}; } map> todo; for (const auto i : rep_impl((N))) { auto [x, y, v] = XYV[i]; todo[x].push_back({x, y, v}); } vector T; for (auto& [x, _] : todo) { T.push_back(x - (P - 1)); T.push_back(x + 1); } unique_inplace(T); auto seg = DynamicLazySegTree, MAdd, operate, default_factory>(3.2e9); ll res = 0; for (auto t : T) { for (auto [x, y, v] : todo[t + (P - 1)]) { assert(0 <= y - (Q - 1)); seg.apply(y - (Q - 1), y + 1, v); } for (auto [x, y, v] : todo[t - 1]) { assert(0 <= y - (Q - 1)); seg.apply(y - (Q - 1), y + 1, -v); } ll nres = seg.fold_all(); chmax(res, nres); } seg.clear(); return res; } int main() { int64_t N, A; read(N, A); vector XYV(N); for (const auto i : rep_impl((N))) { int64_t x, y, v; read(x, y, v); XYV[i] = {x, y, v}; } ll res = 0; for (const auto P : rep_impl((A), (A + 2))) for (const auto Q : rep_impl((A), (A + 2))) chmax(res, resolve(N, P, Q, XYV)); print(res); }