結果
| 問題 |
No.3214 small square
|
| コンテスト | |
| ユーザー |
dp_ijk
|
| 提出日時 | 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);
}
dp_ijk