結果

問題 No.2676 A Tourist
コンテスト
ユーザー zawakasu
提出日時 2026-10-17 18:42:27
言語 C++23
(gcc 15.3.0 + boost 1.92.0 + ACL)
コンパイル:
g++-15 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 438 ms / 5,000 ms
+ 92µs
コード長 16,381 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 2,033 ms
コンパイル使用メモリ 250,644 KB
実行使用メモリ 89,184 KB
最終ジャッジ日時 2026-10-17 18:42:53
合計ジャッジ時間 25,498 ms
ジャッジサーバーID
(参考情報)
judge5_0 / judge4_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 31
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

/*
 * Disclaimer: All code enclosed within “namespace zawa” is available at the following link.
 * https://zawa-tin.github.io/cp-documentation/
 */
#include <iostream>
#include <iomanip>
#include <cassert>
#include <vector>
#include <algorithm>
#include <utility>
#include <numeric>
#include <tuple>
#include <ranges>
#include <random>
// #include "Src/Number/IntegerDivision.hpp"
// #include "Src/Utility/BinarySearch.hpp"
// #include "Src/Sequence/CompressedSequence.hpp"
// #include "Src/Sequence/RunLengthEncoding.hpp"

namespace zawa {

template <class T>
class AdditiveGroup {
public:
    using Element = T;
    static constexpr T identity() noexcept {
        return T{};
    }
    static constexpr T operation(T l,T r) noexcept {
        return l + r;
    }
    static constexpr T inverse(T v) noexcept {
        return -v;
    }
    template <class U>
    static constexpr T power(T v,U exp) noexcept {
        return v * static_cast<T>(exp);
    }
};

} // namespace zawa


#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 <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

namespace zawa {

namespace concepts {

template <class T>
concept Inversible = requires {
    typename T::Element;
    { T::inverse(std::declval<typename T::Element>()) } -> std::same_as<typename T::Element>;
};

template <class T>
concept Group = Monoid<T> and Inversible<T>;

} // namespace Concept

} // namespace zawa

#include <ostream>
#include <functional>
#include <type_traits>

namespace zawa {

template <concepts::Monoid Monoid>
class FenwickTree {
public:

    using VM = Monoid;
    
    using V = typename VM::Element;

    FenwickTree() = default;

    explicit FenwickTree(usize n) : m_n{ n }, m_bitwidth{ std::__lg(n) + 1 }, m_a(n, VM::identity()), m_dat(n + 1, VM::identity()) {
        m_dat.shrink_to_fit();
        m_a.shrink_to_fit();
    }

    explicit FenwickTree(const std::vector<V>& a) : m_n{ a.size() }, m_bitwidth{ std::__lg(a.size()) + 1 }, m_a(a), m_dat(a.size() + 1, VM::identity()) {
        m_dat.shrink_to_fit();  
        m_a.shrink_to_fit();
        for (i32 i{} ; i < static_cast<i32>(m_n) ; i++) {
            addDat(i, a[i]);
        }
    }

    inline usize size() const noexcept {
        return m_n;
    }

    // return a[i]
    const V& get(usize i) const noexcept {
        assert(i < size());
        return m_a[i];
    }

    // return a[i]
    const V& operator[](usize i) const noexcept {
        assert(i < size());
        return m_a[i];
    }

    // a[i] <- a[i] + v
    void operation(usize i, const V& v) {
        assert(i < size());
        addDat(i, v);
        m_a[i] = VM::operation(m_a[i], v);
    }

    // a[i] <- v
    void assign(usize i, const V& v) requires concepts::Inversible<Monoid> {
        assert(i < size());
        addDat(i, VM::operation(VM::inverse(m_a[i]), v));
        m_a[i] = v;
    }

    // return a[0] + a[1] + ... + a[r - 1]
    V prefixProduct(usize r) const {
        assert(r <= size());
        return product(r);
    }

    // return a[l] + a[l + 1] ... + a[r - 1]
    V product(usize l, usize r) const requires concepts::Inversible<Monoid> {
        assert(l <= r and r <= size());
        return VM::operation(VM::inverse(product(l)), product(r));
    }

    template <class Function>
    usize maxRight(usize l, const Function& f) const requires concepts::Inversible<Monoid> {
        static_assert(std::is_convertible_v<decltype(f), std::function<bool(V)>>, "maxRight's argument f must be function bool(T)");
        assert(l <= size());
        assert(f(VM::identity()));
        V sum{ VM::inverse(product(l)) }; 
        usize r{};
        for (usize bit{ m_bitwidth } ; bit ; ) {
            bit--;
            usize nxt{ r | (1u << bit) };
            if (nxt < m_dat.size() and (nxt <= l or f(VM::operation(sum, m_dat[nxt])))) {
                sum = VM::operation(sum, m_dat[nxt]);
                r = std::move(nxt);
            }
        }
        assert(l <= r);
        return r;
    }

    template <class Function>
    usize minLeft(usize r, const Function& f) const requires concepts::Inversible<Monoid> {
        static_assert(std::is_convertible_v<decltype(f), std::function<bool(V)>>, "minLeft's argument f must be function bool(T)");
        assert(r <= size());
        assert(f(VM::identity()));
        V sum{ product(r) };
        usize l{};
        for (usize bit{ m_bitwidth } ; bit ; ) {
            bit--;
            usize nxt{ l | (1u << bit) };
            if (nxt <= r and not f(VM::operation(VM::inverse(m_dat[nxt]), sum))) {
                sum = VM::operation(VM::inverse(m_dat[nxt]), sum);
                l = std::move(nxt);
            }
        }
        assert(l <= r);
        return l;
    }

    // debug print
    friend std::ostream& operator<<(std::ostream& os, const FenwickTree& ft) {
        for (usize i{} ; i <= ft.size() ; i++) {
            os << ft.prefixProduct(i) << (i == ft.size() ? "" : " ");
        }
        return os;
    }

private:

    usize m_n{};

    usize m_bitwidth{};

    std::vector<V> m_a, m_dat;

    constexpr i32 lsb(i32 x) const noexcept {
        return x & -x;
    }
    
    // a[i] <- a[i] + v
    void addDat(i32 i, const V& v) {
        assert(0 <= i and i < static_cast<i32>(m_n));
        for ( i++ ; i < static_cast<i32>(m_dat.size()) ; i += lsb(i)) {
            m_dat[i] = VM::operation(m_dat[i], v);
        }
    }

    // return a[0] + a[1] + .. + a[i - 1]
    V product(i32 i) const {
        assert(0 <= i and i <= static_cast<i32>(m_n));
        V res{ VM::identity() };
        for ( ; i > 0 ; i -= lsb(i)) {
            res = VM::operation(res, m_dat[i]);
        }
        return res;
    }

};

} // namespace zawa
// #include "Src/DataStructure/SegmentTree/SegmentTree.hpp"
// #include "Src/DataStructure/DisjointSetUnion/DisjointSetUnion.hpp"
// #include "Src/DataStructure/Heap/BinaryHeap.hpp"


#include <cmath>
#include <limits>
#include <optional>

namespace zawa {

template <std::integral V>
class HeavyLightDecomposition {
public:

    HeavyLightDecomposition() = default;

    HeavyLightDecomposition(std::vector<std::vector<V>> T, V root = 0u) 
        : m_n{T.size()}, m_par(m_n), m_top(m_n), m_idx(m_n), m_out(m_n),
        m_inv(m_n), m_bottom(m_n),  m_size(m_n, usize{1}), m_dep(m_n) {

            auto dfs1 = [&](auto dfs, V v, V p, usize d) -> usize {
                m_par[v] = p;
                m_dep[v] = d;
                if (p != INVALID) {
                    for (usize i = 0 ; i + 1 < T[v].size() ; i++) 
                        if (T[v][i] == p) {
                            std::swap(T[v][i], T[v].back());
                            break;
                        }
                    assert(T[v].back() == p);
                    T[v].pop_back();
                }
                for (V x : T[v])
                    m_size[v] += dfs(dfs, x, v, d + 1);
                for (usize i = 1 ; i < T[v].size() ; i++) 
                    if (m_size[T[v][0]] < m_size[T[v][i]])
                        std::swap(T[v][0], T[v][i]);
                return m_size[v];
            };

            auto dfs2 = [&](auto dfs, V v, V idx, V top) -> V {
                m_idx[v] = idx++;
                m_inv[m_idx[v]] = v;
                m_top[v] = top;
                if (T[v].size()) {
                    idx = dfs(dfs, T[v][0], idx, top);
                    for (usize i = 1 ; i < T[v].size() ; i++)
                        idx = dfs(dfs, T[v][i], idx, T[v][i]);
                }
                return m_out[v] = idx;
            };

            dfs1(dfs1, root, INVALID, 0u);
            dfs2(dfs2, root, 0u, root);

            for (usize i = 0 ; i < m_n ; i++)
                if (m_dep[m_bottom[m_top[i]]] < m_dep[i])
                    m_bottom[m_top[i]] = i;
        }

    inline usize size() const noexcept {
        return m_n;
    }

    usize size(V v) const noexcept {
        assert(v < (V)size());
        return m_size[v];
    }

    usize depth(V v) const noexcept {
        assert(v < (V)size());
        return m_dep[v];
    }

    V parent(V v) const noexcept {
        assert(v < (V)size());
        return m_par[v];
    }

    V index(V v) const noexcept {
        assert(v < (V)size());
        return m_idx[v];
    }

    V operator[](V v) const noexcept {
        assert(v < (V)size());
        return m_idx[v];
    }

    V top(V v) const noexcept {
        assert(v < (V)size());
        return m_top[v];
    }

    V bottom(V v) const noexcept {
        assert(v < (V)size());
        return m_bottom[m_top[v]];
    }

    std::pair<V, V> heavyPath(V v) const {
        assert(v < (V)size());
        return {top(v), bottom(v)};
    }

    std::vector<std::pair<V, V>> decomp(V s, V t) const {
        assert(s < (V)size());
        assert(t < (V)size());
        std::vector<std::pair<V, V>> res, ser;
        while (m_top[s] != m_top[t]) {
            if (m_dep[m_top[s]] >= m_dep[m_top[t]]) {
                res.emplace_back(s, m_top[s]);
                s = m_top[s];
                if (m_par[s] != INVALID) s = m_par[s];
            }
            else {
                ser.emplace_back(m_top[t], t);
                t = m_top[t];
                if (m_par[t] != INVALID) t = m_par[t];
            }
        }
        res.emplace_back(s, t);
        std::reverse(ser.begin(), ser.end());
        res.insert(res.end(), ser.begin(), ser.end()); 
        return res;
    }

    std::vector<std::pair<V, V>> operator()(V s, V t) const {
        return decomp(s, t);
    }

    // first > secondのときは逆向きのパス
    // 逆向きになる可能性がある都合上、閉区間で返される。
    std::vector<std::pair<V,V>> pathQuery(V s, V t) const {
        auto res = decomp(s,t);
        for (auto& [u,v] : res) {
            u = m_idx[u];
            v = m_idx[v];
        }
        return res;
    }

    std::pair<V,V> subtreeQuery(V v) const {
        assert(v < (V)size());
        return {m_idx[v],m_out[v]};
    }

    V lca(V u, V v) const {
        assert(u < (V)size());
        assert(v < (V)size());
        while (m_top[u] != m_top[v]) {
            if (m_dep[m_top[u]] >= m_dep[m_top[v]]) {
                u = m_top[u];
                if (m_par[u] != INVALID) u = m_par[u];
            }
            else {
                v = m_top[v];
                if (m_par[v] != INVALID) v = m_par[v];
            }
        }
        return (m_dep[u] <= m_dep[v] ? u : v);
    }

    // is p ancestor of v ?
    bool isAncestor(V v, V p) const {
        assert(v < (V)size());
        assert(p < (V)size());
        return m_idx[p] <= m_idx[v] and m_out[v] <= m_out[p];
    }

    std::optional<V> levelAncestor(V v, usize step) const {
        assert(v < (V)size());
        if (step > m_dep[v]) return std::nullopt;
        while (true) {
            usize dist{m_dep[v] - m_dep[m_top[v]]};
            if (dist >= step) break;
            step -= dist + 1;
            v = m_par[m_top[v]];
        }
        step = (m_dep[v] - m_dep[m_top[v]]) - step;
        return m_inv[m_idx[m_top[v]] + step];
    }

    std::optional<V> jump(V s, V t, usize step) const {
        assert(s < (V)size());
        assert(t < (V)size());
        V uu{INVALID}, vv{INVALID};
        usize d{};
        for (auto [u, v] : decomp(s, t)) {
            usize dist{std::max(m_dep[u], m_dep[v]) - std::min(m_dep[u], m_dep[v])};
            if (dist >= step) {
                uu = u;
                vv = v;
                d = dist;
                break;
            }
            step -= dist + 1;
        }
        if (uu == INVALID) 
            return std::nullopt;
        if (m_dep[uu] <= m_dep[vv])
            return m_inv[m_idx[uu] + step];
        else
            return m_inv[m_idx[vv] + (d - step)];
    }

    usize distance(V s, V t) const {
        assert(s < (V)size());
        assert(t < (V)size());
        usize res{};
        for (auto [u, v] : decomp(s, t)) {
            if (m_dep[u] > m_dep[v]) std::swap(u, v);
            res += m_dep[v] - m_dep[u] + 1;
        }
        return --res;
    }

private:

    static constexpr V INVALID{static_cast<V>(-1)};

    usize m_n{};

    std::vector<V> m_par{}, m_top{}, m_idx{}, m_out{}, m_inv{}, m_bottom{};

    std::vector<usize> m_size{}, m_dep{};
};

} // namespace zawa
namespace zawa {}
using namespace zawa;
// #include "atcoder/modint"
// using mint = atcoder::modint998244353;
// #include <array>
// #include <bit>
// #include <bitset>
// #include <climits>
// #include <cmath>
// #include <set>
// #include <unordered_set>
// #include <map>
// #include <unordered_map>
// #include <optional>
// #include <queue>
// #include <stack>
// #include <deque>
// #pragma GCC target("avx2")
// #pragma GCC optimize("O3")
// #pragma GCC optimize("unroll-loops")
using namespace std;
template <class T, class U>
ostream& operator<<(ostream& os, const pair<T, U>& p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0 ; i < ssize(v) ; i++)
        os << v[i] << (i + 1 == ssize(v) ? "" : " ");
    return os;
}
/*
 *
 */
int main() {
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    cout << fixed << setprecision(20);
#if !defined DEBUG
    int N,Q;
    cin >> N >> Q;
    vector<long long> A(N);
    for (auto& x : A)
        cin >> x;
    vector<vector<int>> G(N);
    for (int i = 0 ; i < N-1 ; i++) {
        int u,v;
        cin >> u >> v;
        u--; v--;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    HeavyLightDecomposition hld{G};
    FenwickTree<AdditiveGroup<long long>> fen1(N),fen2(N);
    vector<long long> B=A;
    for (int i = 0 ; i < N ; i++) {
        fen1.operation(hld[i],A[i]);
        if (i)
            B[hld.parent(i)]+=A[i];
    }
    for (int i = 0 ; i < N ; i++)
        fen2.operation(hld[i],B[i]);
    auto pathsum=[&](FenwickTree<AdditiveGroup<long long>>& fen,int u,int v)->long long {
        long long res=0;
        for (auto [l,r] : hld.pathQuery(u,v)) {
            if (l>r)
                swap(l,r);
            res+=fen.product(l,r+1);
        }
        return res;
    };
    while (Q--) {
        int t;
        cin >> t;
        if (t == 0) {
            int v,x;
            cin >> v >> x;
            v--;
            B[v]-=A[v];
            if (v)
                B[hld.parent(v)]-=A[v];
            A[v]+=x;
            if (v)
                B[hld.parent(v)]+=A[v];
            B[v]+=A[v];
            fen1.assign(hld[v],A[v]);
            fen2.assign(hld[v],B[v]);
            if (v)
                fen2.assign(hld[hld.parent(v)],B[hld.parent(v)]);
        }
        else if (t == 1) {
            int u,v;
            cin >> u >> v;
            u--; v--;
            int l=hld.lca(u,v);
            long long ans=pathsum(fen2,u,v);
            if (l)
                ans+=A[hld.parent(l)];
            if (u != l)
                ans-=pathsum(fen1,u,hld.jump(l,u,1).value());
            if (v != l)
                ans-=pathsum(fen1,v,hld.jump(l,v,1).value());
            cout << ans << '\n';
        }
        else
            assert(0);
    }
#else
    mt19937_64 mt{random_device{}()};
    for (int testcase = 0 ; ; ) {
        cerr << "----------" << ++testcase << "----------" << endl;
        
        auto a = solve(), b = naive();
        if (a != b) {
            // print testcase

            cerr << "you: " << a << endl;
            cout << "correct: " << b << endl;
            exit(0);
        }
    }
#endif
}
0