結果
問題 |
No.3214 small square
|
ユーザー |
![]() |
提出日時 | 2025-07-25 23:13:39 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 2,138 ms / 3,000 ms |
コード長 | 17,089 bytes |
コンパイル時間 | 2,535 ms |
コンパイル使用メモリ | 194,800 KB |
実行使用メモリ | 52,076 KB |
最終ジャッジ日時 | 2025-07-25 23:14:42 |
合計ジャッジ時間 | 56,737 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 40 |
ソースコード
#include <algorithm> #include <array> #include <bit> #include <cassert> #include <cmath> #include <concepts> #include <cstddef> #include <cstdint> #include <cstdlib> #include <deque> #include <functional> #include <iomanip> #include <iostream> #include <iterator> #include <limits> #include <map> #include <numeric> #include <optional> #include <queue> #include <random> #include <ranges> #include <set> #include <sstream> #include <stdexcept> #include <string> #include <tuple> #include <type_traits> #include <utility> #include <vector> 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 <typename T> constexpr auto rep_iota_impl(T start, T stop) noexcept { return std::views::iota(start, (start < stop ? stop : start)); } template <typename T = int64_t> constexpr auto rep_impl(auto start, auto stop) noexcept { return rep_iota_impl<T>(start, stop); } template <typename T = int64_t> constexpr auto rep_impl(auto stop) noexcept { return rep_iota_impl<T>(0, stop); } template <typename T = int64_t> constexpr auto rep_impl(auto start, auto stop, auto step) noexcept { struct Rep { struct Iter { T cur; const T stop; const T step; constexpr Iter& operator++() noexcept { cur += step; return *this; } constexpr T operator*() const noexcept { return cur; } constexpr bool operator==(std::default_sentinel_t) const noexcept { return (step > 0) ? cur >= stop : cur <= stop; } }; Iter iter; constexpr Rep(T start, T stop, T step) noexcept : iter{start, stop, step} { assert(step != 0); } constexpr Iter begin() const noexcept { return iter; } constexpr std::default_sentinel_t end() const noexcept { return {}; } }; return Rep(start, stop, step); } template <class... Ts> inline void read(Ts&... ts) { (std::cin >> ... >> ts); } template <class T, class U> inline bool chmax(T& a, U b) { if (a < b) { a = b; return true; } return false; } template <class T, class U> inline bool chmin(T& a, U b) { if (a > b) { a = b; return true; } return false; } template <typename T> void unique_inplace(std::vector<T>& 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()); } using std::vector; template <typename T, typename U> vector<T> cumsum(vector<T>& A, U initial) { vector<T> res(A.size() + 1); res[0] = initial; for (const auto i : rep_impl((1), (res.size()))) res[i] = res[i - 1] + A[i - 1]; return res; } using std::vector; template <typename X> 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 <typename T> void put(const T& t) { std::cout << t; } template <typename... Ts> 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; using std::vector; template <typename Data> struct ElementProxy { using T = Data::value_type; private: Data& data; const int index; public: constexpr ElementProxy(Data& data_, int index) noexcept : data(data_), index(index) {} operator T() const { return data.get(index); } ElementProxy& operator=(const T& x) { data.set(index, x); return *this; } ElementProxy& operator+=(const T& x) { data.set(index, data.get(index) + x); return *this; } ElementProxy& operator-=(const T& x) { data.set(index, data.get(index) - x); return *this; } ElementProxy& operator*=(const T& x) { data.set(index, data.get(index) * x); return *this; } ElementProxy& operator/=(const T& x) { data.set(index, data.get(index) / x); return *this; } template <typename D = Data> requires requires { typename D::lazy_type; } ElementProxy& apply(const typename D::lazy_type& a) { data.apply(index, a); return *this; } template <typename D = Data> requires requires { typename D::lazy_type; } ElementProxy& operator%=(const typename D::lazy_type& a) { data.apply(index, index + 1, a); return *this; } }; template <typename MX_, typename MA_, auto operate> struct LazySegTree { using ll = int64_t; using MX = MX_; using MA = MA_; using X = typename MX::T; using A = typename MA::T; using value_type = X; using lazy_type = A; constexpr static bool action_commutative = []() { if constexpr (requires { MA::commutative; }) { return MA::commutative; } return false; }(); constexpr static bool is_zero(const A& a) { if constexpr (requires { &MA::is_unit; }) { return MA::is_unit(a); } else { return a == MA::unit(); } } int N, log, size; vector<X> data; vector<A> lazy; LazySegTree() {} LazySegTree(ll N) { build(N); } LazySegTree(ll N, auto f) { build(N, f); } template <typename S> LazySegTree(const vector<S>& A) { build(A); } void build(ll N) { build(N, [](ll i) -> X { return MX::unit(); }); } template <typename S> void build(const vector<S>& A) { build(A.size(), [&](ll i) -> X { return A[i]; }); } void build(ll N_, auto f) { N = N_, log = 1; while ((1 << log) < N) ++log; size = 1 << log; data.assign(size << 1, MX::unit()); lazy.assign(size, MA::unit()); for (const auto i : rep_impl((N))) data[size + i] = f(i); for (const auto i : rep_impl((size - 1), (0), (-1))) update(i); } inline void operate_inplace(int v, A a) { assert(1 <= v && v < size * 2); if constexpr (std::is_invocable_v<decltype(operate), X, A>) { data[v] = operate(data[v], a); } else { int bitlen = std::bit_width(uint32_t(v)); ll width = ll(1) << (log - (bitlen - 1)); data[v] = operate(data[v], a, width); } } inline void apply_subtree(int v, A a) { assert(1 <= v && v < size * 2); operate_inplace(v, a); if (v < size) lazy[v] = MA::op(lazy[v], a); } template <bool has_lazy = 1> inline void update(int p) { assert(1 <= p && p < size); data[p] = MX::op(data[p << 1], data[p << 1 | 1]); if constexpr (action_commutative && has_lazy) { operate_inplace(p, lazy[p]); } } inline void push_lazy(int p) { if (p == 0) return; assert(1 <= p && p < size); if (is_zero(lazy[p])) return; apply_subtree(p << 1, lazy[p]); apply_subtree(p << 1 | 1, lazy[p]); lazy[p] = MA::unit(); } inline void rectify_leaf(int j) { assert(size <= j && j < size * 2); for (int h = log; h >= 1; h--) push_lazy(j >> h); } void set(ll i, X x) { assert(0 <= i && i < N); int j = i + size; rectify_leaf(j); data[j] = x; for (int h = 1; h <= log; h++) update<0>(j >> h); } X get(ll i) { assert(0 <= i && i < N); int j = i + size; rectify_leaf(j); return data[j]; } vector<X> get_all() { for (const auto i : rep_impl((1), (size))) push_lazy(i); return {data.begin() + size, data.begin() + size + N}; } auto copy() const { LazySegTree<MX, MA, operate> res(N); res.data = data; res.lazy = lazy; return res; } vector<X> to_vector() const { return copy().get_all(); } X fold(ll L, ll R) { chmax(L, 0); chmin(R, N); if (not(L < R)) return MX::unit(); assert(0 <= L && L < R && R <= N); if (R == N) R = size; L += size, R += size; for (int i = log; i >= 1; i--) { if (((L >> i) << i) != L) push_lazy(L >> i); if (((R >> i) << i) != R) push_lazy((R - 1) >> i); } X vL = MX::unit(), vR = MX::unit(); while (L < R) { if (L & 1) vL = MX::op(vL, data[L++]); if (R & 1) vR = MX::op(data[--R], vR); L >>= 1, R >>= 1; } return MX::op(vL, vR); } X fold_all() const { return data[1]; } void apply(int L, int R, A a) { chmax(L, 0); chmin(R, N); if (not(L < R)) return; assert(0 <= L && L < R && R <= N); if (R == N) R = size; L += size, R += size; const std::pair<int, int> backup = {L, R}; if constexpr (!action_commutative) { for (int i = log; i >= 1; i--) { if (((L >> i) << i) != L) push_lazy(L >> i); if (((R >> i) << i) != R) push_lazy((R - 1) >> i); } } while (L < R) { if (L & 1) apply_subtree(L++, a); if (R & 1) apply_subtree(--R, a); L >>= 1, R >>= 1; } std::tie(L, R) = backup; for (int i = 1; i <= log; i++) { if (((L >> i) << i) != L) { update(L >> i); } if (((R >> i) << i) != R) { update((R - 1) >> i); } } } void apply_all(A a) { apply(0, size, a); } int max_right(int l, auto is_ok) { assert(0 <= l && l <= N); assert(is_ok(MX::unit())); if (l == N) return N; l += size; for (int i = log; i >= 1; i--) push_lazy(l >> i); X sm = MX::unit(); do { while (l % 2 == 0) l >>= 1; if (!is_ok(MX::op(sm, data[l]))) { while (l < size) { push_lazy(l); l = (2 * l); if (is_ok(MX::op(sm, data[l]))) { sm = MX::op(sm, data[l++]); } } return l - size; } sm = MX::op(sm, data[l++]); } while ((l & -l) != l); return N; } int min_left(int r, auto is_ok) { assert(0 <= r && r <= N); assert(is_ok(MX::unit())); if (r == 0) return 0; r += size; for (int i = log; i >= 1; i--) push_lazy((r - 1) >> i); X sm = MX::unit(); do { r--; while (r > 1 && (r % 2)) r >>= 1; if (!is_ok(MX::op(data[r], sm))) { while (r < size) { push_lazy(r); r = (2 * r + 1); if (is_ok(MX::op(data[r], sm))) { sm = MX::op(data[r--], sm); } } return r + 1 - size; } sm = MX::op(data[r], sm); } while ((r & -r) != r); return 0; } class RangeProxy { private: LazySegTree<MX, MA, operate>& seg; const int L, R; public: explicit RangeProxy(LazySegTree<MX, MA, operate>& seg, int L, int R) : seg(seg), L(L), R(R) {} RangeProxy& operator%=(const A& a) { seg.apply(L, R, a); return *this; } operator X() && { return seg.fold(L, R); } operator X() & { return seg.fold(L, R); } }; public: auto operator()(int index) { assert(0 <= index && index < N); return ElementProxy<LazySegTree<MX, MA, operate>>(*this, index); } RangeProxy operator()(int L, int R) { return RangeProxy(*this, L, R); } X operator[](std::pair<int, int> LR) { auto [L, R] = LR; return fold(L, R); } X operator[](int index) { assert(0 <= index && index < N); return get(index); } }; constexpr int64_t INF = 23e17; template <typename X, X INF> 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) { return M + a; } using std::pair; using std::tuple; using std::vector; template <typename T, bool unique, bool lookup = 0> struct Compress { using ll = int64_t; vector<T> X{}; vector<ll> counter{}; bool frozen = false; Compress() {} template <typename U> Compress(const vector<U>& A) { extend(A); } void add(T x) { frozen = false; X.push_back(x); } template <typename U> void extend(const vector<U>& A) { frozen = false; for (const auto& x : A) { X.push_back(x); } } void build() { if (frozen) return; if (!std::is_sorted(X.begin(), X.end())) { std::sort(X.begin(), X.end()); } if constexpr (unique) { unique_inplace(X); } if constexpr (lookup) { if (!X.empty()) { auto min_ = X.front(); auto max_ = X.back(); counter.clear(); counter.resize(max_ - min_ + 1, 0); for (const auto& x : X) { counter[x - min_] += 1; } counter = cumsum(counter, 0LL); } } else { frozen = cumsum(counter, 0LL).empty(); } frozen = true; } ll bisect_left(T x) const { assert(frozen); if (X.empty()) return 0; if (x <= X.front()) return 0; if (x > X.back()) return X.size(); if constexpr (lookup) { return counter[x - X.front()]; } else { return std::distance(X.begin(), std::lower_bound(X.begin(), X.end(), x)); } } ll bisect_right(T x) const { assert(frozen); if (X.empty()) return 0; if (x < X.front()) return 0; if (x >= X.back()) return X.size(); if constexpr (lookup) { return counter[x - X.front() + 1]; } else { return std::distance(X.begin(), std::upper_bound(X.begin(), X.end(), x)); } } template <bool inclusive = 0> ll bisect(T x) const { if constexpr (inclusive) { return bisect_right(x); } else { return bisect_left(x); } } bool contains(T x) const { assert(frozen); ll i = bisect_left(x); if (i == X.size()) return false; return X[i] == x; } ll size() const { return X.size(); } T operator[](int64_t idx) const { return X[idx]; } }; struct Point { ll x, y, v; }; ll resolve(ll N, ll P, ll Q, vector<Point> 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<ll, vector<Point>> todo; for (const auto i : rep_impl((N))) { auto [x, y, v] = XYV[i]; todo[x].push_back({x, y, v}); } set<ll> T; for (auto& [x, _] : todo) { T.insert(x - (P - 1)); T.insert(x + 1); } Compress<ll, 1> comp; for (auto [x, y, v] : XYV) { comp.add(y - (Q - 1)); comp.add(y + 1); } comp.build(); auto seg = LazySegTree<MMax<ll, INF>, MAdd<ll>, operate>(comp.size()); seg.apply(0, comp.size(), INF); ll res = 0; for (auto t : T) { for (auto [x, y, v] : todo[t + (P - 1)]) { assert(0 <= y - (Q - 1)); seg.apply(comp.bisect(y - (Q - 1)), comp.bisect(y + 1), v); } for (auto [x, y, v] : todo[t - 1]) { assert(0 <= y - (Q - 1)); seg.apply(comp.bisect(y - (Q - 1)), comp.bisect(y + 1), -v); } ll nres = seg.fold_all(); chmax(res, nres); } return res; } int main() { int64_t N, A; read(N, A); vector<Point> 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); }