結果
| 問題 |
No.3185 Three Abs
|
| コンテスト | |
| ユーザー |
zawakasu
|
| 提出日時 | 2025-06-20 21:55:41 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 502 ms / 2,000 ms |
| コード長 | 9,673 bytes |
| コンパイル時間 | 1,652 ms |
| コンパイル使用メモリ | 146,800 KB |
| 実行使用メモリ | 16,560 KB |
| 最終ジャッジ日時 | 2025-06-20 21:55:58 |
| 合計ジャッジ時間 | 12,757 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 30 |
ソースコード
#include <iostream>
#include <iomanip>
#include <cassert>
#include <vector>
#include <algorithm>
#include <utility>
#include <numeric>
#include <tuple>
#include <ranges>
namespace ranges = std::ranges;
namespace views = std::views;
// #include "Src/Number/IntegerDivision.hpp"
// #include "Src/Utility/BinarySearch.hpp"
#include <cstdint>
#include <cstddef>
namespace zawa {
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using usize = std::size_t;
} // namespace zawa
#include <iterator>
#include <limits>
namespace zawa {
template <class T>
class CompressedSequence {
public:
static constexpr u32 NotFound = std::numeric_limits<u32>::max();
CompressedSequence() = default;
template <class InputIterator>
CompressedSequence(InputIterator first, InputIterator last) : comped_(first, last), f_{} {
std::sort(comped_.begin(), comped_.end());
comped_.erase(std::unique(comped_.begin(), comped_.end()), comped_.end());
comped_.shrink_to_fit();
f_.reserve(std::distance(first, last));
for (auto it{first} ; it != last ; it++) {
f_.emplace_back(std::distance(comped_.begin(), std::lower_bound(comped_.begin(), comped_.end(), *it)));
}
}
CompressedSequence(const std::vector<T>& A) : CompressedSequence(A.begin(), A.end()) {}
inline usize size() const noexcept {
return comped_.size();
}
u32 operator[](const T& v) const {
return std::distance(comped_.begin(), std::lower_bound(comped_.begin(), comped_.end(), v));
}
u32 upper_bound(const T& v) const {
return std::distance(comped_.begin(), std::upper_bound(comped_.begin(), comped_.end(), v));
}
u32 find(const T& v) const {
u32 i = std::distance(comped_.begin(), std::lower_bound(comped_.begin(), comped_.end(), v));
return i == comped_.size() or comped_[i] != v ? NotFound : i;
}
bool contains(const T& v) const {
u32 i = std::distance(comped_.begin(), std::lower_bound(comped_.begin(), comped_.end(), v));
return i < comped_.size() and comped_[i] == v;
}
u32 at(const T& v) const {
u32 res = find(v);
assert(res != NotFound);
return res;
}
inline u32 map(u32 i) const noexcept {
assert(i < f_.size());
return f_[i];
}
inline T inverse(u32 i) const noexcept {
assert(i < size());
return comped_[i];
}
inline std::vector<T> comped() const noexcept {
return comped_;
}
private:
std::vector<T> comped_;
std::vector<u32> f_;
};
} // namespace zawa
// #include "Src/Sequence/RunLengthEncoding.hpp"
// #include "Src/Algebra/Group/AdditiveGroup.hpp"
// #include "Src/DataStructure/FenwickTree/FenwickTree.hpp"
#include <concepts>
namespace zawa {
namespace concepts {
template <class T>
concept Semigroup = requires {
typename T::Element;
{ T::operation(std::declval<typename T::Element>(), std::declval<typename T::Element>()) } -> std::same_as<typename T::Element>;
};
} // namespace concepts
} // namespace zawa
namespace zawa {
namespace concepts {
template <class T>
concept Identitiable = requires {
typename T::Element;
{ T::identity() } -> std::same_as<typename T::Element>;
};
template <class T>
concept Monoid = Semigroup<T> and Identitiable<T>;
} // namespace
} // namespace zawa
#include <functional>
#include <type_traits>
#include <ostream>
namespace zawa {
template <concepts::Monoid Monoid>
class SegmentTree {
public:
using Value = typename Monoid::Element;
private:
constexpr u32 left(u32 v) const {
return v << 1;
}
constexpr u32 right(u32 v) const {
return v << 1 | 1;
}
constexpr u32 parent(u32 v) const {
return v >> 1;
}
usize n_;
std::vector<Value> dat_;
public:
SegmentTree() = default;
SegmentTree(u32 n) : n_{ n }, dat_(n << 1, Monoid::identity()) {
assert(n_);
}
SegmentTree(const std::vector<Value>& dat) : n_{ dat.size() }, dat_(dat.size() << 1, Monoid::identity()) {
assert(n_);
for (u32 i{} ; i < n_ ; i++) {
dat_[i + n_] = dat[i];
}
for (u32 i{static_cast<u32>(n_) - 1} ; i ; i--) {
dat_[i] = Monoid::operation(dat_[left(i)], dat_[right(i)]);
}
}
Value get(u32 i) const {
assert(i < n_);
return dat_[i + n_];
}
void operation(u32 i, const Value& value) {
assert(i < n_);
i += n_;
dat_[i] = Monoid::operation(dat_[i], value);
while (i = parent(i), i) {
dat_[i] = Monoid::operation(dat_[left(i)], dat_[right(i)]);
}
}
void set(u32 i, const Value& value) {
assert(i < n_);
i += n_;
dat_[i] = value;
while (i = parent(i), i) {
dat_[i] = Monoid::operation(dat_[left(i)], dat_[right(i)]);
}
}
Value product(u32 l, u32 r) const {
assert(l <= r and r <= n_);
Value leftValue{ Monoid::identity() }, rightValue{ Monoid::identity() };
for (l += n_, r += n_ ; l < r ; l = parent(l), r = parent(r)) {
if (l & 1) {
leftValue = Monoid::operation(leftValue, dat_[l++]);
}
if (r & 1) {
rightValue = Monoid::operation(dat_[--r], rightValue);
}
}
return Monoid::operation(leftValue, rightValue);
}
template <class Function>
u32 maxRight(u32 l, const Function& f) {
assert(l < n_);
static_assert(std::is_convertible_v<decltype(f), std::function<bool(Value)>>, "maxRight's argument f must be function bool(T)");
assert(f(Monoid::identity()));
u32 res{l}, width{1};
Value prod{ Monoid::identity() };
// 現在の見ている頂点の幅をwidthで持つ
// 境界がある頂点を含む部分木の根を探す
// (折り返す時は必要以上の幅を持つ根になるが、widthを持っているのでオーバーしない)
for (l += n_ ; res + width <= n_ ; l = parent(l), width <<= 1) if (l & 1) {
if (not f(Monoid::operation(prod, dat_[l]))) break;
res += width;
prod = Monoid::operation(prod, dat_[l++]);
}
// 根から下って、境界を発見する
while (l = left(l), width >>= 1) {
if (res + width <= n_ and f(Monoid::operation(prod, dat_[l]))) {
res += width;
prod = Monoid::operation(prod, dat_[l++]);
}
}
return res;
}
template <class Function>
u32 minLeft(u32 r, const Function& f) const {
assert(r <= n_);
static_assert(std::is_convertible_v<decltype(f), std::function<bool(Value)>>, "minLeft's argument f must be function bool(T)");
assert(f(Monoid::identity()));
u32 res{r}, width{1};
Value prod{ Monoid::identity() };
for (r += n_ ; res >= width ; r = parent(r), width <<= 1) if (r & 1) {
if (not f(Monoid::operation(dat_[r - 1], prod))) break;
res -= width;
prod = Monoid::operation(prod, dat_[--r]);
}
while (r = left(r), width >>= 1) {
if (res >= width and f(Monoid::operation(dat_[r - 1], prod))) {
res -= width;
prod = Monoid::operation(dat_[--r], prod);
}
}
return res;
}
friend std::ostream& operator<<(std::ostream& os, const SegmentTree& st) {
for (u32 i{1} ; i < 2 * st.n_ ; i++) {
os << st.dat_[i] << (i + 1 == 2 * st.n_ ? "" : " ");
}
return os;
}
};
} // namespace zawa
// #include "Src/DataStructure/DisjointSetUnion/DisjointSetUnion.hpp"
using namespace zawa;
// #include "atcoder/modint"
// using mint = atcoder::modint998244353;
const long long INF = (long long)1e18;
struct M {
using Element = long long;
static Element identity() { return -INF; }
static Element operation(Element L, Element R) { return std::max(L, R); }
};
int N;
long long A[200020];
long long solve() {
std::vector<long long> S(N + 1);
for (int i = 0 ; i < N ; i++) S[i + 1] = S[i] + A[i];
CompressedSequence<long long> comp{S};
auto ladd = [&](long long v) {
return comp.inverse(comp.size() - 1) - v;
};
auto radd = [&](long long v) {
return v - comp.inverse(0);
};
SegmentTree<M> segL(comp.size()), segR(comp.size());
segL.set(comp.at(0LL), ladd(0LL));
segR.set(comp.at(0LL), radd(0LL));
std::vector<long long> dp(N + 1);
for (int i = 0 ; i < N ; i++) {
const long long l = segL.product(0, comp.at(S[i + 1]) + 1) - ladd(S[i + 1]);
const long long r = segR.product(comp.at(S[i + 1]) + 1, comp.size()) - radd(S[i + 1]);
dp[i + 1] = std::max(l, r);
segL.operation(comp.at(S[i + 1]), std::abs(S[i + 1]) + ladd(S[i + 1]));
segR.operation(comp.at(S[i + 1]), std::abs(S[i + 1]) + radd(S[i + 1]));
}
// for (auto d : dp) std::cout << d << ' ';
// std::cout << std::endl;
long long ans = 0LL;
for (int i = N - 1 ; i >= 0 ; i--) {
ans = std::max(ans, dp[i] + std::abs(S[N] - S[i]));
}
return ans;
}
int main() {
std::cin.tie(nullptr);
std::cout.tie(nullptr);
std::ios::sync_with_stdio(false);
int T;
std::cin >> T;
while (T--) {
std::cin >> N;
for (int i = 0 ; i < N ; i++) std::cin >> A[i];
std::cout << solve() << '\n';
}
}
zawakasu