This documentation is automatically generated by competitive-verifier/competitive-verifier
#define PROBLEM "https://judge.yosupo.jp/problem/vertex_add_path_sum"
#include "include/mtl/hld.hpp"
#include "include/mtl/segment_tree.hpp"
#include <bits/stdc++.h>
using namespace std;
struct Sum {
long long x;
Sum(long long x=0):x(x) {}
Sum operator*(const Sum& o) const {
return Sum(x+o.x);
}
};
int main() {
int n,q; cin>>n>>q;
vector<int> A(n);
for (int i = 0; i < n; i++) cin>>A[i];
Hld T(n);
for (int i = 0; i < n-1; i++) {
int u,v; cin>>u>>v;
T.add_edge(u,v);
}
T.build();
vector<int> B(n);
for (int i = 0; i < n; i++) B[T.in[i]] = A[i];
SegmentTree<Sum> path_sum(B.begin(), B.end());
for (int i = 0; i < q; i++) {
int t; cin>>t;
if (t == 0) {
int p,x; cin>>p>>x;
auto tp = T.in[p];
path_sum.set(tp, {path_sum.get(tp).x+x});
} else {
int u,v; cin>>u>>v;
auto ret = T.query(u,v,[&](int l, int r) {
return path_sum.query(l, r);
}).x;
cout << ret << endl;
}
}
}
#line 1 "test/yosupo/vertex_add_path_sum.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/vertex_add_path_sum"
#line 2 "include/mtl/hld.hpp"
#include <cstddef>
#include <vector>
struct Hld {
int r,n;
std::vector<std::vector<int>> edge;
std::vector<int> size, in, out, head, rev, par, depth, clen;
private:
void dfs_sz(int v, int p, int d) {
par[v] = p;
size[v] = 1;
if (!edge[v].empty() and edge[v][0] == p)
std::swap(edge[v][0], edge[v].back());
for (auto& t:edge[v]) {
if (t == p) continue;
dfs_sz(t, v, d+1);
size[v] += size[t];
if (size[edge[v][0]] < size[t])
std::swap(edge[v][0], t);
}
}
void dfs_hld(int v, int p, int& times) {
in[v] = times++;
rev[in[v]] = v;
clen[v] = 1;
if (!edge[v].empty() and edge[v][0] != p) {
int t = edge[v][0];
head[t] = head[v];
depth[t] = depth[v];
dfs_hld(t, v, times);
clen[v] += clen[t];
}
for (size_t i = 1; i < edge[v].size(); i++) {
int t = edge[v][i];
if (t == p) continue;
head[t] = t;
depth[t] = depth[v] + 1;
dfs_hld(t, v, times);
}
out[v] = times;
}
public:
Hld(int n) : r(0), n(n), edge(n), size(n), in(n, -1), out(n, -1), head(n, -1), rev(n, -1), par(n, -1), depth(n, -1), clen(n) {}
inline void add_edge(int a, int b) {
edge[a].push_back(b);
edge[b].push_back(a);
}
void build(int root = 0) {
r = root;
dfs_sz(root, -1, 0);
int t = 0;
head[root] = root;
depth[root] = 0;
dfs_hld(root, -1, t);
}
inline int lca(int a, int b) const {
if (depth[a] > depth[b]) std::swap(a, b);
while (depth[a] < depth[b]) {
b = par[head[b]];
}
while (head[a] != head[b]) {
a = par[head[a]];
b = par[head[b]];
}
return in[a] < in[b] ? a : b;
}
private:
template<class Query, class ReverseQuery>
auto _query(int u, int v, Query Q, ReverseQuery RQ, bool include_lca) const -> decltype(Q(0,0)) {
using T = decltype(Q(0,0));
T um, vm;
auto u_up = [&]() {
um = um * (T)RQ(in[head[u]], in[u]+1);
u = par[head[u]];
};
auto v_up = [&]() {
vm = (T)Q(in[head[v]], in[v]+1) * vm;
v = par[head[v]];
};
while (depth[u] > depth[v])
u_up();
while (depth[u] < depth[v])
v_up();
while (head[u] != head[v]) {
u_up();
v_up();
}
if (in[u] < in[v]) {
int l = include_lca ? in[u] : in[u]+1;
return um * (T)Q(l, in[v]+1) * vm;
} else {
int l = include_lca ? in[v] : in[v]+1;
return um * (T)RQ(l, in[u]+1) * vm;
}
}
public:
template<class Query, class ReverseQuery>
auto query(int u, int v, Query Q, ReverseQuery RQ, bool include_lca = true) const -> decltype(Q(0,0)) {
return _query(u, v, Q, RQ, include_lca);
}
/// Query for commutative monoid
template<class Query>
auto query(int u, int v, Query Q, bool include_lca = true) const -> decltype(Q(0,0)) {
return _query(u, v, Q, Q, include_lca);
}
template<class Set, class T>
void set(int i, Set S, T&& val) const {
S(in[i], std::forward<T>(val));
}
template<typename Upd, typename T>
void update(int u, int v, Upd U, const T& val, bool include_lca = true) const {
if (depth[u] > depth[v]) std::swap(u,v);
auto up = [&](int& v) {
U(in[head[v]], in[v]+1, val);
v = par[head[v]];
};
while (depth[u] < depth[v]) {
up(v);
}
while (head[u] != head[v]) {
up(u);
up(v);
}
if (in[u] > in[v]) std::swap(u,v);
int l = include_lca ? in[u] : in[u]+1;
U(l, in[v]+1, val);
}
public:
template<class Add, class Sum>
void subtree_build(Add A, Sum S) const {
dfs_subtree_build(A, S, r);
}
private:
template<class Add, class Sum>
void dfs_subtree_build(Add A, Sum S, int u) const {
for (size_t i = 0; i < edge[u].size(); i++) {
auto v = edge[u][i];
if (v == par[u]) continue;
dfs_subtree_build(A, S, v);
if (i > 0)
A(in[u], S(in[v], in[v]+clen[v]));
}
}
public:
template<class T, class Sum>
T subtree_sum(int r, Sum S) const {
return (T)S(in[r], in[r]+clen[r]);
}
template<class T, class Add>
void subtree_point_add(int u, Add A, const T& val) const {
while (u != -1) {
A(in[u], val);
u = par[head[u]];
}
}
};
#line 2 "include/mtl/bit_manip.hpp"
#include <cstdint>
#include <cassert>
#if __cplusplus >= 202002L
#ifndef MTL_CPP20
#define MTL_CPP20
#endif
#include <bit>
#endif
namespace bm {
/// Count 1s for each 8 bits
inline constexpr uint64_t popcnt_e8(uint64_t x) {
x = (x & 0x5555555555555555) + ((x>>1) & 0x5555555555555555);
x = (x & 0x3333333333333333) + ((x>>2) & 0x3333333333333333);
x = (x & 0x0F0F0F0F0F0F0F0F) + ((x>>4) & 0x0F0F0F0F0F0F0F0F);
return x;
}
/// Count 1s
inline constexpr unsigned popcnt(uint64_t x) {
#ifdef MTL_CPP20
return std::popcount(x);
#else
return (popcnt_e8(x) * 0x0101010101010101) >> 56;
#endif
}
/// Alias to mtl::popcnt(x)
constexpr unsigned popcount(uint64_t x) {
return popcnt(x);
}
/// Count trailing 0s. s.t. *11011000 -> 3
inline constexpr unsigned ctz(uint64_t x) {
#ifdef MTL_CPP20
return std::countr_zero(x);
#else
return popcnt((x & (-x)) - 1);
#endif
}
/// Alias to mtl::ctz(x)
constexpr unsigned countr_zero(uint64_t x) {
return ctz(x);
}
/// Count trailing 1s. s.t. *11011011 -> 2
inline constexpr unsigned cto(uint64_t x) {
#ifdef MTL_CPP20
return std::countr_one(x);
#else
return ctz(~x);
#endif
}
/// Alias to mtl::cto(x)
constexpr unsigned countr_one(uint64_t x) {
return cto(x);
}
inline constexpr unsigned ctz8(uint8_t x) {
return x == 0 ? 8 : popcnt_e8((x & (-x)) - 1);
}
/// [00..0](8bit) -> 0, [**..*](not only 0) -> 1
inline constexpr uint8_t summary(uint64_t x) {
constexpr uint64_t hmask = 0x8080808080808080ull;
constexpr uint64_t lmask = 0x7F7F7F7F7F7F7F7Full;
auto a = x & hmask;
auto b = x & lmask;
b = hmask - b;
b = ~b;
auto c = (a | b) & hmask;
c *= 0x0002040810204081ull;
return uint8_t(c >> 56);
}
/// Extract target area of bits
inline constexpr uint64_t bextr(uint64_t x, unsigned start, unsigned len) {
uint64_t mask = len < 64 ? (1ull<<len)-1 : 0xFFFFFFFFFFFFFFFFull;
return (x >> start) & mask;
}
/// 00101101 -> 00111111 -count_1s-> 6
inline constexpr unsigned log2p1(uint8_t x) {
if (x & 0x80)
return 8;
uint64_t p = uint64_t(x) * 0x0101010101010101ull;
p -= 0x8040201008040201ull;
p = ~p & 0x8080808080808080ull;
p = (p >> 7) * 0x0101010101010101ull;
p >>= 56;
return p;
}
/// 00101100 -mask_mssb-> 00100000 -to_index-> 5
inline constexpr unsigned mssb8(uint8_t x) {
assert(x != 0);
return log2p1(x) - 1;
}
/// 00101100 -mask_lssb-> 00000100 -to_index-> 2
inline constexpr unsigned lssb8(uint8_t x) {
assert(x != 0);
return popcnt_e8((x & -x) - 1);
}
/// Count leading 0s. 00001011... -> 4
inline constexpr unsigned clz(uint64_t x) {
#ifdef MTL_CPP20
return std::countl_zero(x);
#else
if (x == 0)
return 64;
auto i = mssb8(summary(x));
auto j = mssb8(bextr(x, 8 * i, 8));
return 63 - (8 * i + j);
#endif
}
/// Alias to mtl::clz(x)
constexpr unsigned countl_zero(uint64_t x) {
return clz(x);
}
/// Count leading 1s. 11110100... -> 4
inline constexpr unsigned clo(uint64_t x) {
#ifdef MTL_CPP20
return std::countl_one(x);
#else
return clz(~x);
#endif
}
/// Alias to mtl::clo(x)
constexpr unsigned countl_one(uint64_t x) {
return clo(x);
}
inline constexpr unsigned clz8(uint8_t x) {
return x == 0 ? 8 : 7 - mssb8(x);
}
inline constexpr uint64_t bit_reverse(uint64_t x) {
x = ((x & 0x00000000FFFFFFFF) << 32) | ((x & 0xFFFFFFFF00000000) >> 32);
x = ((x & 0x0000FFFF0000FFFF) << 16) | ((x & 0xFFFF0000FFFF0000) >> 16);
x = ((x & 0x00FF00FF00FF00FF) << 8) | ((x & 0xFF00FF00FF00FF00) >> 8);
x = ((x & 0x0F0F0F0F0F0F0F0F) << 4) | ((x & 0xF0F0F0F0F0F0F0F0) >> 4);
x = ((x & 0x3333333333333333) << 2) | ((x & 0xCCCCCCCCCCCCCCCC) >> 2);
x = ((x & 0x5555555555555555) << 1) | ((x & 0xAAAAAAAAAAAAAAAA) >> 1);
return x;
}
/// Check if x is power of 2. 00100000 -> true, 00100001 -> false
constexpr bool has_single_bit(uint64_t x) noexcept {
#ifdef MTL_CPP20
return std::has_single_bit(x);
#else
return x != 0 && (x & (x - 1)) == 0;
#endif
}
/// Bit width needs to represent x. 00110110 -> 6
constexpr int bit_width(uint64_t x) noexcept {
#ifdef MTL_CPP20
return std::bit_width(x);
#else
return 64 - clz(x);
#endif
}
/// Ceil power of 2. 00110110 -> 01000000
constexpr uint64_t bit_ceil(uint64_t x) {
#ifdef MTL_CPP20
return std::bit_ceil(x);
#else
if (x == 0) return 1;
return 1ull << bit_width(x - 1);
#endif
}
/// Floor power of 2. 00110110 -> 00100000
constexpr uint64_t bit_floor(uint64_t x) {
#ifdef MTL_CPP20
return std::bit_floor(x);
#else
if (x == 0) return 0;
return 1ull << (bit_width(x) - 1);
#endif
}
} // namespace bm
#line 5 "include/mtl/segment_tree.hpp"
#include <stack>
#if __cplusplus >= 202002L
#include <concepts>
template<class M>
concept SegmentTreeMonoid = requires (M m) {
{m * m} -> std::same_as<M>;
};
#endif
template <class M>
class SegmentTree {
#if __cplusplus >= 202002L
static_assert(SegmentTreeMonoid<M>);
#endif
public:
using monoid_type = M;
using value_type = monoid_type;
private:
size_t size_;
std::vector<value_type> tree_;
public:
explicit SegmentTree(size_t size) : size_(size), tree_(size*2) {}
template <class Iter>
explicit SegmentTree(Iter begin, Iter end) : SegmentTree(std::distance(begin, end)) {
if (size_==0) return;
std::copy(begin, end, tree_.begin() + size_);
for (size_t i = size_-1; i > 0; i--)
tree_[i] = tree_[i<<1] * tree_[(i<<1)+1];
}
value_type get(size_t index) const {
return tree_[size_ + index];
}
value_type operator[](size_t index) const {
return get(index);
}
private:
template<class T>
void _set(size_t index, T&& val) {
auto i = size_ + index;
tree_[i] = std::forward<T>(val);
i >>= 1;
while (i > 0) {
tree_[i] = tree_[i<<1] * tree_[(i<<1)+1];
i >>= 1;
}
}
public:
template<class T>
void set(size_t index, T&& val) {
return _set(index, std::forward<T>(val));
}
void set(size_t index, const value_type& val) {
_set(index, val);
}
void set(size_t index, value_type&& val) {
_set(index, std::move(val));
}
value_type query(size_t l, size_t r) const {
value_type lhs,rhs;
for (auto _l = l+size_, _r = r+size_; _l < _r; _l>>=1, _r>>=1) {
if (_l&1) lhs = lhs * tree_[_l++];
if (_r&1) rhs = tree_[--_r] * rhs;
}
return lhs * rhs;
}
template<class F>
size_t max_right(size_t begin, size_t end, F f) const {
if (begin == end) return end;
monoid_type p;
std::stack<std::pair<size_t, monoid_type>> rps;
auto l = size_ + begin;
auto r = size_ + end;
while (l < r and f(p * tree_[l])) {
if (l&1) p = p * tree_[l++];
if (r&1) {
rps.emplace(r, tree_[r-1]);
r--;
}
l>>=1; r>>=1;
}
if (l >= r) {
while (rps.size()) {
auto& [r, rp] = rps.top();
if (!f(p * rp)) {
l = r-1;
break;
}
p = p * rp;
rps.pop();
}
if (rps.empty()) return end;
}
while (l < size_) {
assert(!f(p * tree_[l]));
l <<= 1;
if (f(p * tree_[l]))
p = p * tree_[l++];
}
return l - size_;
}
template<class F>
size_t min_left(size_t begin, size_t end, F f) const {
if (end == begin) return begin;
monoid_type p;
std::stack<std::pair<size_t, monoid_type>> lps;
auto l = size_ + begin;
auto r = size_ + end;
while (l < r and f(tree_[r-1] * p)) {
if (l&1) {
lps.emplace(l, tree_[l]);
l++;
}
if (r&1) p = tree_[r-1] * p;
l>>=1; r>>=1;
}
if (l >= r) {
while (lps.size()) {
auto& [l, lp] = lps.top();
if (!f(lp * p)) {
r = l+1;
break;
}
p = lp * p;
lps.pop();
}
if (lps.empty()) return begin;
}
while (r <= size_) {
assert(!f(tree_[r-1] * p));
r <<= 1;
if (f(tree_[r-1] * p))
p = tree_[--r] * p;
}
return r - size_;
}
template<bool (*F)(value_type)>
size_t min_left(size_t begin, size_t end) const {
return min_left(begin, [](value_type x) { return F(x); });
}
};
#line 4 "test/yosupo/vertex_add_path_sum.test.cpp"
#include <bits/stdc++.h>
using namespace std;
struct Sum {
long long x;
Sum(long long x=0):x(x) {}
Sum operator*(const Sum& o) const {
return Sum(x+o.x);
}
};
int main() {
int n,q; cin>>n>>q;
vector<int> A(n);
for (int i = 0; i < n; i++) cin>>A[i];
Hld T(n);
for (int i = 0; i < n-1; i++) {
int u,v; cin>>u>>v;
T.add_edge(u,v);
}
T.build();
vector<int> B(n);
for (int i = 0; i < n; i++) B[T.in[i]] = A[i];
SegmentTree<Sum> path_sum(B.begin(), B.end());
for (int i = 0; i < q; i++) {
int t; cin>>t;
if (t == 0) {
int p,x; cin>>p>>x;
auto tp = T.in[p];
path_sum.set(tp, {path_sum.get(tp).x+x});
} else {
int u,v; cin>>u>>v;
auto ret = T.query(u,v,[&](int l, int r) {
return path_sum.query(l, r);
}).x;
cout << ret << endl;
}
}
}
Env | Name | Status | Elapsed | Memory |
---|---|---|---|---|
g++ | almost_line_00 |
![]() |
1236 ms | 185 MB |
g++ | almost_line_01 |
![]() |
1647 ms | 169 MB |
g++ | example_00 |
![]() |
6 ms | 3 MB |
g++ | line_00 |
![]() |
1203 ms | 165 MB |
g++ | line_01 |
![]() |
1504 ms | 219 MB |
g++ | long-path-decomposition_killer_00 |
![]() |
1163 ms | 58 MB |
g++ | max_random_00 |
![]() |
1133 ms | 58 MB |
g++ | max_random_01 |
![]() |
1272 ms | 58 MB |
g++ | max_random_02 |
![]() |
1336 ms | 58 MB |
g++ | random_00 |
![]() |
895 ms | 46 MB |
g++ | random_01 |
![]() |
1112 ms | 54 MB |
g++ | random_02 |
![]() |
642 ms | 9 MB |
g++ | random_03 |
![]() |
446 ms | 51 MB |
g++ | random_04 |
![]() |
373 ms | 34 MB |
g++ | small_00 |
![]() |
7 ms | 4 MB |
g++ | small_01 |
![]() |
6 ms | 3 MB |
g++ | small_02 |
![]() |
6 ms | 3 MB |
g++ | small_03 |
![]() |
6 ms | 3 MB |
g++ | small_04 |
![]() |
7 ms | 4 MB |
clang++ | almost_line_00 |
![]() |
1111 ms | 80 MB |
clang++ | almost_line_01 |
![]() |
1108 ms | 77 MB |
clang++ | example_00 |
![]() |
6 ms | 3 MB |
clang++ | line_00 |
![]() |
1071 ms | 77 MB |
clang++ | line_01 |
![]() |
1246 ms | 86 MB |
clang++ | long-path-decomposition_killer_00 |
![]() |
1095 ms | 58 MB |
clang++ | max_random_00 |
![]() |
1144 ms | 58 MB |
clang++ | max_random_01 |
![]() |
1561 ms | 58 MB |
clang++ | max_random_02 |
![]() |
2896 ms | 58 MB |
clang++ | random_00 |
![]() |
900 ms | 46 MB |
clang++ | random_01 |
![]() |
1025 ms | 54 MB |
clang++ | random_02 |
![]() |
524 ms | 9 MB |
clang++ | random_03 |
![]() |
441 ms | 51 MB |
clang++ | random_04 |
![]() |
375 ms | 34 MB |
clang++ | small_00 |
![]() |
7 ms | 4 MB |
clang++ | small_01 |
![]() |
6 ms | 3 MB |
clang++ | small_02 |
![]() |
6 ms | 3 MB |
clang++ | small_03 |
![]() |
6 ms | 3 MB |
clang++ | small_04 |
![]() |
7 ms | 4 MB |