Procon

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub K-Yoshizawa/Procon

:heavy_check_mark: verify/LC-VertexAddPathSum.test.cpp

Depends on

Code

#define PROBLEM "https://judge.yosupo.jp/problem/vertex_add_path_sum"

#include "../Library/Template.hpp"
#include "../Library/Tree/HeavyLightDecomposition.hpp"
#include "../Library/DataStructure/SegmentTree.hpp"

int main(){
    cin.tie(0)->sync_with_stdio(false);
    int N, Q; cin >> N >> Q;
    vector<ll> a(N); cin >> a;
    auto T = InputTree(N, 0);

    HeavyLightDecomposition hld(T);
    hld.SortVertex(a);
    SegmentTree<ll> seg(a, [](ll l, ll r){return l + r;}, 0LL, true);
    while(Q--){
        int t; cin >> t;
        if(t == 0){
            int p, x; cin >> p >> x;
            seg.Apply(hld[p], seg[hld[p]] + x);
        }
        else{
            int u, v; cin >> u >> v;
            ll ans = 0;
            for(auto &path : hld.PathQuery(u, v)){
                ans += seg.Fold(path.head_index, path.tail_index);
            }
            cout << ans << '\n';
        }
    }
}
#line 1 "verify/LC-VertexAddPathSum.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/vertex_add_path_sum"

#line 2 "Library/Template.hpp"

#line 2 "Library/Common.hpp"

/**
 * @file Common.hpp
 */

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cstdint>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;

using ll = int64_t;
using ull = uint64_t;

constexpr const ll INF = (1LL << 62) - (3LL << 30) - 1;
#line 4 "Library/Template.hpp"

inline bool YnPrint(bool flag){cout << (flag ? "Yes" : "No") << '\n'; return flag;}
inline bool YNPrint(bool flag){cout << (flag ? "YES" : "NO") << '\n'; return flag;}
template<typename Container>
inline void Sort(Container &container){sort(container.begin(), container.end());}
template<typename Container>
inline void ReverseSort(Container &container){sort(container.rbegin(), container.rend());}
template<typename Container>
inline void Reverse(Container &container){reverse(container.begin(), container.end());}
template<typename Value>
inline int PopCount(const Value &value){return __builtin_popcount(value);}
template<typename Value>
inline Value Floor(Value numerator, Value denominator){if(denominator < 0) numerator *= -1, denominator *= -1; return numerator < 0 ? (numerator + 1) / denominator - 1 : numerator / denominator;}
template<typename Value>
inline Value Ceil(Value numerator, Value denominator){if(denominator < 0) numerator *= -1, denominator *= -1; return numerator > 0 ? (numerator - 1) / denominator + 1 : numerator / denominator;}
template<typename Value>
inline int LowerBoundIndex(const vector<Value> &container, const Value &value){return distance(container.begin(), lower_bound(container.begin(), container.end(), value));}
template<typename Value>
inline int UpperBoundIndex(const vector<Value> &container, const Value &value){return distance(container.begin(), upper_bound(container.begin(), container.end(), value));}
template<typename Value>
inline bool Between(const Value &lower, const Value &x, const Value &higher){return lower <= x && x <= higher;}
template<typename Value>
inline bool InGrid(const Value &y, const Value &x, const Value &ymax, const Value &xmax){return Between(0, y, ymax - 1) && Between(0, x, xmax - 1);}
template<typename Value>
inline Value Median(const Value &a, const Value &b, const Value &c){return Between(b, a, c) || Between(c, a, b) ? a : (Between(a, b, c) || Between(c, b, a) ? b : c);}
template<typename Value>
inline Value Except(Value &src, Value &cond, Value &excp){return (src == cond ? excp : src);}

template<class Value>
bool chmin(Value &src, const Value &cmp){if(src > cmp){src = cmp; return true;} return false;}
template<class Value>
bool chmax(Value &src, const Value &cmp){if(src < cmp){src = cmp; return true;} return false;}
template<typename Value>
inline Value min(vector<Value> &v){return *min_element((v).begin(), (v).end());}
template<typename Value>
inline Value max(vector<Value> &v){return *max_element((v).begin(), (v).end());}

const int dx4[4] = {1, 0, -1, 0};
const int dy4[4] = {0, -1, 0, 1};
const int dx8[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const int dy8[8] = {0, -1, -1, -1, 0, 1, 1, 1};

vector<pair<int, int>> adjacent(int current_y, int current_x, int max_y, int max_x, bool dir_8 = false){
    vector<pair<int, int>> ret;
    for(int d = 0; d < 4 * (1 + dir_8); ++d){
        int next_y = current_y + (dir_8 ? dy8[d] : dy4[d]);
        int next_x = current_x + (dir_8 ? dx8[d] : dx4[d]);
        if(InGrid(next_y, next_x, max_y, max_x)){
            ret.emplace_back(next_y, next_x);
        }
    }
    return ret;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p){
    os << p.first << " " << p.second;
    return os;
}

template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, vector<T> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? " " : "");
    }
    return os;
}

template <typename T>
ostream &operator<<(ostream &os, vector<vector<T>> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? "\n" : "");
    }
    return os;
}

template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (int i = 0; i < v.size(); ++i) is >> v[i];
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, set<T> &v){
    for (auto &u : v){
        os << u << " ";
    }
    return os;
}

template<typename T1, typename T2>
vector<pair<T1, T2>> AssembleVectorPair(vector<T1> &v1, vector<T2> &v2){
    assert(v1.size() == v2.size());
    vector<pair<T1, T2>> v;
    for(int i = 0; i < v1.size(); ++i) v.push_back({v1[i], v2[i]});
    return v;
}

template<typename T1, typename T2>
pair<vector<T1>, vector<T2>> DisassembleVectorPair(vector<pair<T1, T2>> &v){
    vector<T1> v1;
    vector<T2> v2;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return p.first;});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return p.second;});
    return {v1, v2};
}

template<typename T1, typename T2, typename T3>
tuple<vector<T1>, vector<T2>, vector<T3>> DisassembleVectorTuple(vector<tuple<T1, T2, T3>> &v){
    vector<T1> v1;
    vector<T2> v2;
    vector<T3> v3;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return get<0>(p);});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return get<1>(p);});
    transform(v.begin(), v.end(), back_inserter(v3), [](auto p){return get<2>(p);});
    return {v1, v2, v3};
}

template<typename T1 = int, typename T2 = T1>
pair<vector<T1>, vector<T2>> InputVectorPair(int size){
    vector<pair<T1, T2>> v(size);
    for(auto &[p, q] : v) cin >> p >> q;
    return DisassembleVectorPair(v);
}

template<typename T1 = int, typename T2 = T1, typename T3 = T1>
tuple<vector<T1>, vector<T2>, vector<T3>> InputVectorTuple(int size){
    vector<tuple<T1, T2, T3>> v(size);
    for(auto &[p, q, r] : v) cin >> p >> q >> r;
    return DisassembleVectorTuple(v);
}
#line 2 "Library/Tree/Tree.hpp"

#line 2 "Library/Graph/Graph.hpp"

#line 4 "Library/Graph/Graph.hpp"

using Vertex = int;

template<typename WeightType = int32_t>
struct Edge{
    public:
    Edge() = default;

    Edge(Vertex from_, Vertex to_, WeightType weight_ = 1, int idx_ = -1) :
        from(from_), to(to_), cost(weight_), idx(idx_){}
    
    bool operator<(const Edge<WeightType> &e) const {return cost < e.cost;}

    operator int() const {return to;}

    Vertex from, to;
    WeightType cost;
    int idx;
};

template<typename WeightType = int32_t>
class Graph{
    public:
    Graph() = default;

    Graph(int V) : edge_size_(0), adjacent_list_(V){}
    
    inline void AddUndirectedEdge(Vertex u, Vertex v, WeightType w = 1){
        int idx = edge_size_++;
        adjacent_list_[u].push_back(Edge<WeightType>(u, v, w, idx));
        adjacent_list_[v].push_back(Edge<WeightType>(v, u, w, idx));
    }
    
    inline void AddDirectedEdge(Vertex u, Vertex v, WeightType w = 1){
        int idx = edge_size_++;
        adjacent_list_[u].push_back(Edge<WeightType>(u, v, w, idx));
    }

    inline size_t VertexSize() const {
        return adjacent_list_.size();
    }

    inline size_t EdgeSize() const {
        return edge_size_;
    }

    inline vector<Edge<WeightType>> &operator[](const Vertex v){
        return adjacent_list_[v];
    }

    inline const vector<Edge<WeightType>> &operator[](const Vertex v) const {
        return adjacent_list_[v];
    }
    
    private:
    size_t edge_size_;
    vector<vector<Edge<WeightType>>> adjacent_list_;
};

template<typename WeightType = int32_t>
Graph<WeightType> InputGraph(int N, int M, int padding = -1, bool weighted = false, bool directed = false){
    Graph<WeightType> G(N);
    for(int i = 0; i < M; ++i){
        Vertex u, v; WeightType w = 1;
        cin >> u >> v, u += padding, v += padding;
        if(weighted) cin >> w;
        if(directed) G.AddDirectedEdge(u, v, w);
        else G.AddUndirectedEdge(u, v, w);
    }
    return G;
}
#line 4 "Library/Tree/Tree.hpp"

template<typename WeightType = int32_t>
Graph<WeightType> InputTree(int V, int padding = -1, bool weighted = false){
    Graph<WeightType> G(V);
    for(int i = 0; i < V - 1; ++i){
        Vertex u, v; WeightType w = 1;
        cin >> u >> v, u += padding, v += padding;
        if(weighted) cin >> w;
        G.AddUndirectedEdge(u, v, w);
    }
    return G;
}

template<typename WeightType = int32_t>
Graph<WeightType> InputRootedTreeChild(int V, int padding = -1){
    Graph<WeightType> G(V);
    for(Vertex u = 0; u < V; ++u){
        int k; cin >> k;
        for(int i = 0; i < k; ++i){
            Vertex v; cin >> v, v += padding;
            G.AddUndirectedEdge(u, v);
        }
    }
    return G;
}

template<typename WeightType = int32_t>
Graph<WeightType> InputRootedTreeParent(int V, int padding = -1){
    Graph<WeightType> G(V);
    for(Vertex u = 1; u < V; ++u){
        Vertex v; cin >> v, v += padding;
        G.AddUndirectedEdge(u, v);
    }
    return G;
}

template<typename WeightType = int32_t>
vector<vector<Vertex>> RootedTreeAdjacentList(const Graph<WeightType> &T, const Vertex r = 0){
    int V = T.VertexSize();
    vector<vector<Vertex>> ret(V);
    auto rec = [&](auto &self, Vertex u, Vertex p) -> void {
        for(Vertex v : T[u]){
            if(v == p) continue;
            ret[u].push_back(v);
            self(self, v, u);
        }
    };
    rec(rec, r, -1);
    return ret;
}

template<typename WeightType>
vector<Vertex> CalculateTreeParent(Graph<WeightType> &T, Vertex r = 0){
    int V = T.VertexSize();
    vector<Vertex> ret(V, -1);
    auto rec = [&](auto &self, Vertex u) -> void {
        for(Vertex v : T[u]){
            if(v == ret[u]) continue;
            ret[v] = u;
            self(self, v);
        }
    };
    rec(rec, r);
    return ret;
}

template<typename WeightType>
vector<WeightType> CalculateTreeCost(Graph<WeightType> &T, Vertex r = 0){
    int V = T.VertexSize();
    vector<WeightType> ret(V);
    auto rec = [&](auto &self, Vertex u, Vertex p) -> void {
        for(const Edge<WeightType> &e : T[u]){
            Vertex v = e.to;
            if(v == p) continue;
            ret[v] = e.cost;
            self(self, v, u);
        }
    };
    rec(rec, r, -1);
    return ret;
}

template<typename WeightType>
vector<int> CalculateTreeDepth(Graph<WeightType> &T, Vertex r = 0){
    int V = T.VertexSize();
    vector<int> ret(V, 0);
    auto rec = [&](auto &self, Vertex u, Vertex p, int d) -> void {
        ret[u] = d;
        for(Vertex v : T[u]){
            if(v == p) continue;
            self(self, v, u, d + 1);
        }
    };
    rec(rec, r, -1, 0);
    return ret;
}

template<typename WeightType>
vector<WeightType> CalculateTreeDistance(Graph<WeightType> &T, Vertex r = 0){
    int V = T.VertexSize();
    vector<WeightType> ret(V, WeightType(INF));
    auto rec = [&](auto &self, Vertex u) -> void {
        for(const Edge<WeightType> &e : T[u]){
            if(ret[e.to] > ret[u] + e.cost){
                ret[e.to] = ret[u] + e.cost;
                self(self, e.to);
            }
        }
    };
    ret[r] = 0;
    rec(rec, r);
    return ret;
}

template<typename WeightType>
vector<int> CalculateSubtreeSize(Graph<WeightType> &tree, Vertex r = 0){
    int V = tree.VertexSize();
    vector<int> ret(V, 1);
    auto rec = [&](auto self, Vertex u, Vertex p) -> int {
        for(const int v : tree[u]){
            if(v == p) continue;
            ret[u] += self(self, v, u);
        }
        return ret[u];
    };
    rec(rec, r, -1);
    return ret;
}
#line 2 "Library/Tree/HeavyLightDecomposition.hpp"

struct PathSegment{
    PathSegment() = default;
    Vertex head_vertex;
    Vertex tail_vertex;
    int head_index;
    int tail_index;
    bool highest;
    bool reverse;
    friend ostream &operator<<(ostream &os, const PathSegment &p){
        return os << "# Path (" << p.head_vertex << " -> " << p.tail_vertex << ", " << p.head_index << " -> " << p.tail_index << ", " << boolalpha << p.highest << ", " << p.reverse << ")";
    }
};

template<typename WeightType>
class HeavyLightDecomposition{
    public:
    HeavyLightDecomposition(Graph<WeightType> &tree, Vertex r = 0) :
        T(tree), parent(CalculateTreeParent(tree, r)), child(RootedTreeAdjacentList(tree, r)), n((int)tree.VertexSize()), euler_tour_(n), rev_order_(n), depth_(CalculateTreeDepth(tree, r)), belong_hp_id_(n){
        vector<int> ss = CalculateSubtreeSize(T, r);
        for(int i = 0; i < n; ++i){
            if(child[i].empty()) continue;
            nth_element(child[i].begin(), child[i].begin() + 1, child[i].end(), [&](Vertex i, Vertex j){
                return ss[i] > ss[j];
            });
        }
        hp_head_.push_back(r);
        hp_depth_.push_back(0);
        belong_hp_id_[r] = 0;
        timer_ = 0;
        dfs(r, 0, 0);
    }

    Vertex LowestCommonAncestor(Vertex u, Vertex v) const {
        if(PathDepth(u) < PathDepth(v)) swap(u, v);
        while(PathDepth(u) != PathDepth(v)){
            u = parent[Head(u)];
        }
        while(Belong(u) != Belong(v)){
            u = parent[Head(u)];
            v = parent[Head(v)];
        }
        return depth_[u] < depth_[v] ? u : v;
    }

    Vertex LevelAncestor(Vertex v, int k){
        assert(k <= depth_[v]);
        Vertex ret = v;
        while(1){
            int h = Head(ret);
            int x = depth_[ret] - depth_[h];
            if(k <= x){
                ret = RevOrder(PreOrder(ret) - k);
                break;
            }
            ret = parent[h];
            k -= x + 1;
        }
        return ret;
    }

    int Jump(Vertex u, Vertex v, int k){
        Vertex w = LowestCommonAncestor(u, v);
        int p = depth_[u] - depth_[w], q = depth_[v] - depth_[w];
        if(p + q < k || k < 0) return -1;
        if(k <= p) return LevelAncestor(u, k);
        else return LevelAncestor(v, p + q - k);
    }

    vector<PathSegment> PathQuery(Vertex u, Vertex v){
        vector<PathSegment> ret;
        Vertex lca = LowestCommonAncestor(u, v);
        while(Belong(u) != Belong(lca)){
            PathSegment path;
            Vertex h = Head(u);
            path.head_vertex = h, path.tail_vertex = u;
            path.head_index = PreOrder(h), path.tail_index = PreOrder(u) + 1;
            path.highest = false, path.reverse = true;
            ret.push_back(path);
            u = parent[h];
        }
        if(u != lca){
            PathSegment path;
            path.head_vertex = lca, path.tail_vertex = u;
            path.head_index = PreOrder(lca), path.tail_index = PreOrder(u) + 1;
            path.highest = true, path.reverse = true;
            ret.push_back(path);
        }
        int size = ret.size();
        while(Belong(v) != Belong(lca)){
            PathSegment path;
            Vertex h = Head(v);
            path.head_vertex = h, path.tail_vertex = v;
            path.head_index = PreOrder(h), path.tail_index = PreOrder(v) + 1;
            path.highest = false, path.reverse = false;
            ret.push_back(path);
            v = parent[h];
        }
        if(v != lca){
            PathSegment path;
            path.head_vertex = lca, path.tail_vertex = v;
            path.head_index = PreOrder(lca), path.tail_index = PreOrder(v) + 1;
            path.highest = true, path.reverse = false;
            ret.push_back(path);
        }
        if(u == lca && v == lca){
            PathSegment path;
            path.head_vertex = path.tail_vertex = lca;
            path.head_index = PreOrder(lca), path.tail_index = PreOrder(lca) + 1;
            path.highest = true, path.reverse = false;
            ret.push_back(path);
        }
        reverse(ret.begin() + size, ret.end());
        return ret;
    }

    pair<int, int> SubtreeQuery(Vertex v) const {
        return euler_tour_[v];
    }

    template<typename T>
    void SortVertex(vector<T> &A){
        assert(A.size() == n);
        vector<T> sub(n);
        for(int i = 0; i < n; ++i){
            sub[PreOrder(i)] = A[i];
        }
        swap(A, sub);
    }

    int operator[](Vertex v){
        return PreOrder(v);
    }

    const int operator[](Vertex v) const {
        return PreOrder(v);
    }

    private:
    int dfs(Vertex v, int h, int d){
        euler_tour_[v].first = timer_;
        rev_order_[timer_] = v;
        ++timer_;
        int ret = timer_;
        if(!child[v].empty()){
            int c = child[v].size();
            belong_hp_id_[child[v].front()] = h;
            ret = max(ret, dfs(child[v].front(), h, d));
            for(int i = 1; i < c; ++i){
                int nh = (int)hp_head_.size();
                hp_head_.push_back(child[v][i]);
                hp_depth_.push_back(d + 1);
                belong_hp_id_[child[v][i]] = nh;
                ret = max(ret, dfs(child[v][i], nh, d + 1));
            }
        }
        euler_tour_[v].second = ret;
        return ret;
    }

    Vertex Head(Vertex v) const {
        return hp_head_[belong_hp_id_[v]];
    }

    int PathDepth(Vertex v) const {
        return hp_depth_[belong_hp_id_[v]];
    }

    int Belong(Vertex v) const {
        return belong_hp_id_[v];
    }

    Vertex RevOrder(int idx) const {
        return rev_order_[idx];
    }

    int PreOrder(Vertex v) const {
        return euler_tour_[v].first;
    }

    int PostOrder(Vertex v) const {
        return euler_tour_[v].second;
    }

    Graph<WeightType> &T;
    vector<Vertex> parent;
    vector<vector<Vertex>> child;
    int n, timer_;

    vector<pair<int, int>> euler_tour_;
    vector<Vertex> rev_order_;
    vector<int> depth_;

    vector<Vertex> hp_head_; // 各 heavy path の最も根に近い頂点
    vector<int> hp_depth_; // 各 heavy path の深さ
    vector<int> belong_hp_id_; // 各頂点が属する heavy path の番号
};
#line 2 "Library/DataStructure/SegmentTree.hpp"

template<typename Monoid>
class SegmentTree{
    public:
    using F = function<Monoid(Monoid, Monoid)>;
    
    SegmentTree(
        vector<Monoid> &A, 
        F merge, 
        const Monoid &e, 
        bool zero_index = false
    ) : f(merge), id_(e), zero_index_(zero_index){
        size_ = 1;
        while(size_ < (int)A.size()) size_ <<= 1;
        offset_ = size_ - 1;
        data_.resize(2 * size_, id_);
        for(int i = 0; i < (int)A.size(); ++i){
            data_[size_ + i] = A[i];
        }
        for(int i = offset_; i >= 1; --i){
            data_[i] = f(data_[i * 2 + 0], data_[i * 2 + 1]);
        }
    }

    void Apply(int k, Monoid x){
        Validate(k + zero_index_);
        k = offset_ + k + zero_index_;
        data_[k] = x;
        while(k >>= 1){
            data_[k] = f(data_[2 * k], data_[2 * k + 1]);
        }
    }

    Monoid Fold(int l, int r){
        if(l == r) return id_;
        Validate(l + zero_index_);
        Validate(r + zero_index_ - 1);
        int lh = l + zero_index_ + offset_, rh = r + zero_index_ + offset_;
        Monoid al = id_, ar = id_;
        while(lh < rh){
            if(lh & 1) al = f(al, data_[lh++]);
            if(rh & 1) ar = f(data_[--rh], ar);
            lh >>= 1, rh >>= 1;
        }
        return f(al, ar);
    }

    Monoid operator[](const int &k){
        Validate(k + zero_index_);
        return data_[offset_ + k + zero_index_];
    }

    private:
    int size_, offset_, zero_index_;
    vector<Monoid> data_;
    const F f;
    const Monoid id_;

    inline void Validate(int x) const {
        assert(1 <= x && x <= size_);
    }
};
#line 6 "verify/LC-VertexAddPathSum.test.cpp"

int main(){
    cin.tie(0)->sync_with_stdio(false);
    int N, Q; cin >> N >> Q;
    vector<ll> a(N); cin >> a;
    auto T = InputTree(N, 0);

    HeavyLightDecomposition hld(T);
    hld.SortVertex(a);
    SegmentTree<ll> seg(a, [](ll l, ll r){return l + r;}, 0LL, true);
    while(Q--){
        int t; cin >> t;
        if(t == 0){
            int p, x; cin >> p >> x;
            seg.Apply(hld[p], seg[hld[p]] + x);
        }
        else{
            int u, v; cin >> u >> v;
            ll ans = 0;
            for(auto &path : hld.PathQuery(u, v)){
                ans += seg.Fold(path.head_index, path.tail_index);
            }
            cout << ans << '\n';
        }
    }
}
Back to top page