結果

問題 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
権限があれば一括ダウンロードができます

ソースコード

diff #

#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';
    }
}
0