/* * Disclaimer: All code enclosed within “namespace zawa” is available at the following link. * https://zawa-tin.github.io/cp-documentation/ */ #include #include #include #include #include #include #include #include #include #include // #include "Src/Number/IntegerDivision.hpp" // #include "Src/Utility/BinarySearch.hpp" // #include "Src/Sequence/CompressedSequence.hpp" // #include "Src/Sequence/RunLengthEncoding.hpp" namespace zawa { template 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 static constexpr T power(T v,U exp) noexcept { return v * static_cast(exp); } }; } // namespace zawa #include #include 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 namespace zawa { namespace concepts { template concept Semigroup = requires { typename T::Element; { T::operation(std::declval(), std::declval()) } -> std::same_as; }; } // namespace concepts } // namespace zawa namespace zawa { namespace concepts { template concept Identitiable = requires { typename T::Element; { T::identity() } -> std::same_as; }; template concept Monoid = Semigroup and Identitiable; } // namespace } // namespace zawa namespace zawa { namespace concepts { template concept Inversible = requires { typename T::Element; { T::inverse(std::declval()) } -> std::same_as; }; template concept Group = Monoid and Inversible; } // namespace Concept } // namespace zawa #include #include #include namespace zawa { template 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& 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(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 { 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 { assert(l <= r and r <= size()); return VM::operation(VM::inverse(product(l)), product(r)); } template usize maxRight(usize l, const Function& f) const requires concepts::Inversible { static_assert(std::is_convertible_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 usize minLeft(usize r, const Function& f) const requires concepts::Inversible { static_assert(std::is_convertible_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 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(m_n)); for ( i++ ; i < static_cast(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(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 #include #include namespace zawa { template class HeavyLightDecomposition { public: HeavyLightDecomposition() = default; HeavyLightDecomposition(std::vector> 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 heavyPath(V v) const { assert(v < (V)size()); return {top(v), bottom(v)}; } std::vector> decomp(V s, V t) const { assert(s < (V)size()); assert(t < (V)size()); std::vector> 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> operator()(V s, V t) const { return decomp(s, t); } // first > secondのときは逆向きのパス // 逆向きになる可能性がある都合上、閉区間で返される。 std::vector> 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 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 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 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(-1)}; usize m_n{}; std::vector m_par{}, m_top{}, m_idx{}, m_out{}, m_inv{}, m_bottom{}; std::vector m_size{}, m_dep{}; }; } // namespace zawa namespace zawa {} using namespace zawa; // #include "atcoder/modint" // using mint = atcoder::modint998244353; // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #pragma GCC target("avx2") // #pragma GCC optimize("O3") // #pragma GCC optimize("unroll-loops") using namespace std; template ostream& operator<<(ostream& os, const pair& p) { os << '(' << p.first << ',' << p.second << ')'; return os; } template ostream& operator<<(ostream& os, const vector& 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 A(N); for (auto& x : A) cin >> x; vector> 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> fen1(N),fen2(N); vector 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>& 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 }