This documentation is automatically generated by competitive-verifier/competitive-verifier
// competitive-verifier: PROBLEM https://judge.yosupo.jp/problem/vertex_add_subtree_sum
#include <iostream>
#include <vector>
#include "atcoder/fenwicktree.hpp"
#include "tools/hld.hpp"
using ll = long long;
int main() {
std::cin.tie(nullptr);
std::ios_base::sync_with_stdio(false);
ll N, Q;
std::cin >> N >> Q;
std::vector<ll> a(N);
for (auto& a_i : a) std::cin >> a_i;
tools::hld hld(N);
for (ll v = 1; v < N; ++v) {
ll p;
std::cin >> p;
hld.add_edge(p, v);
}
hld.build(0);
atcoder::fenwick_tree<ll> fw(N);
for (ll v = 0; v < N; ++v) {
fw.add(hld.vid2dfs(v), a[v]);
}
for (ll q = 0; q < Q; ++q) {
ll t;
std::cin >> t;
if (t == 0) {
ll u, x;
std::cin >> u >> x;
fw.add(hld.vid2dfs(u), x);
} else {
ll u;
std::cin >> u;
const auto& [l, r] = hld.vsubtree(u);
std::cout << fw.sum(l, r) << '\n';
}
}
return 0;
}
#line 1 "tests/hld/vsubtree.test.cpp"
// competitive-verifier: PROBLEM https://judge.yosupo.jp/problem/vertex_add_subtree_sum
#include <iostream>
#include <vector>
#line 1 "lib/ac-library/atcoder/fenwicktree.hpp"
#include <cassert>
#line 6 "lib/ac-library/atcoder/fenwicktree.hpp"
#line 1 "lib/ac-library/atcoder/internal_type_traits.hpp"
#line 5 "lib/ac-library/atcoder/internal_type_traits.hpp"
#include <numeric>
#include <type_traits>
namespace atcoder {
namespace internal {
#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
typename std::conditional<std::is_same<T, __int128_t>::value ||
std::is_same<T, __int128>::value,
std::true_type,
std::false_type>::type;
template <class T>
using is_unsigned_int128 =
typename std::conditional<std::is_same<T, __uint128_t>::value ||
std::is_same<T, unsigned __int128>::value,
std::true_type,
std::false_type>::type;
template <class T>
using make_unsigned_int128 =
typename std::conditional<std::is_same<T, __int128_t>::value,
__uint128_t,
unsigned __int128>;
template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
is_signed_int128<T>::value ||
is_unsigned_int128<T>::value,
std::true_type,
std::false_type>::type;
template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
std::is_signed<T>::value) ||
is_signed_int128<T>::value,
std::true_type,
std::false_type>::type;
template <class T>
using is_unsigned_int =
typename std::conditional<(is_integral<T>::value &&
std::is_unsigned<T>::value) ||
is_unsigned_int128<T>::value,
std::true_type,
std::false_type>::type;
template <class T>
using to_unsigned = typename std::conditional<
is_signed_int128<T>::value,
make_unsigned_int128<T>,
typename std::conditional<std::is_signed<T>::value,
std::make_unsigned<T>,
std::common_type<T>>::type>::type;
#else
template <class T> using is_integral = typename std::is_integral<T>;
template <class T>
using is_signed_int =
typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
std::true_type,
std::false_type>::type;
template <class T>
using is_unsigned_int =
typename std::conditional<is_integral<T>::value &&
std::is_unsigned<T>::value,
std::true_type,
std::false_type>::type;
template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
std::make_unsigned<T>,
std::common_type<T>>::type;
#endif
template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;
template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;
template <class T> using to_unsigned_t = typename to_unsigned<T>::type;
} // namespace internal
} // namespace atcoder
#line 8 "lib/ac-library/atcoder/fenwicktree.hpp"
namespace atcoder {
// Reference: https://en.wikipedia.org/wiki/Fenwick_tree
template <class T> struct fenwick_tree {
using U = internal::to_unsigned_t<T>;
public:
fenwick_tree() : _n(0) {}
explicit fenwick_tree(int n) : _n(n), data(n) {}
void add(int p, T x) {
assert(0 <= p && p < _n);
p++;
while (p <= _n) {
data[p - 1] += U(x);
p += p & -p;
}
}
T sum(int l, int r) {
assert(0 <= l && l <= r && r <= _n);
return sum(r) - sum(l);
}
private:
int _n;
std::vector<U> data;
U sum(int r) {
U s = 0;
while (r > 0) {
s += data[r - 1];
r -= r & -r;
}
return s;
}
};
} // namespace atcoder
#line 1 "tools/hld.hpp"
#include <algorithm>
#line 6 "tools/hld.hpp"
#include <iterator>
#include <limits>
#line 9 "tools/hld.hpp"
#include <ranges>
#include <stack>
#include <utility>
#line 1 "lib/ac-library/atcoder/dsu.hpp"
#line 7 "lib/ac-library/atcoder/dsu.hpp"
namespace atcoder {
// Implement (union by size) + (path compression)
// Reference:
// Zvi Galil and Giuseppe F. Italiano,
// Data structures and algorithms for disjoint set union problems
struct dsu {
public:
dsu() : _n(0) {}
explicit dsu(int n) : _n(n), parent_or_size(n, -1) {}
int merge(int a, int b) {
assert(0 <= a && a < _n);
assert(0 <= b && b < _n);
int x = leader(a), y = leader(b);
if (x == y) return x;
if (-parent_or_size[x] < -parent_or_size[y]) std::swap(x, y);
parent_or_size[x] += parent_or_size[y];
parent_or_size[y] = x;
return x;
}
bool same(int a, int b) {
assert(0 <= a && a < _n);
assert(0 <= b && b < _n);
return leader(a) == leader(b);
}
int leader(int a) {
assert(0 <= a && a < _n);
if (parent_or_size[a] < 0) return a;
return parent_or_size[a] = leader(parent_or_size[a]);
}
int size(int a) {
assert(0 <= a && a < _n);
return -parent_or_size[leader(a)];
}
std::vector<std::vector<int>> groups() {
std::vector<int> leader_buf(_n), group_size(_n);
for (int i = 0; i < _n; i++) {
leader_buf[i] = leader(i);
group_size[leader_buf[i]]++;
}
std::vector<std::vector<int>> result(_n);
for (int i = 0; i < _n; i++) {
result[i].reserve(group_size[i]);
}
for (int i = 0; i < _n; i++) {
result[leader_buf[i]].push_back(i);
}
result.erase(
std::remove_if(result.begin(), result.end(),
[&](const std::vector<int>& v) { return v.empty(); }),
result.end());
return result;
}
private:
int _n;
// root node: -1 * component size
// otherwise: parent
std::vector<int> parent_or_size;
};
} // namespace atcoder
#line 1 "tools/less_by.hpp"
namespace tools {
template <class F>
class less_by {
private:
F selector;
public:
less_by(const F& selector) : selector(selector) {
}
template <class T>
bool operator()(const T& x, const T& y) const {
return selector(x) < selector(y);
}
};
}
#line 1 "tools/pow2.hpp"
#line 5 "tools/pow2.hpp"
#include <cstddef>
namespace tools {
template <typename T, typename ::std::enable_if<::std::is_unsigned<T>::value, ::std::nullptr_t>::type = nullptr>
constexpr T pow2(const T x) {
return static_cast<T>(1) << x;
}
template <typename T, typename ::std::enable_if<::std::is_signed<T>::value, ::std::nullptr_t>::type = nullptr>
constexpr T pow2(const T x) {
return static_cast<T>(static_cast<typename ::std::make_unsigned<T>::type>(1) << static_cast<typename ::std::make_unsigned<T>::type>(x));
}
}
#line 16 "tools/hld.hpp"
namespace tools {
class hld {
bool m_built;
::std::vector<::std::vector<int>> m_graph;
::std::vector<int> m_edges;
::std::vector<int> m_parent;
::std::vector<int> m_depth;
::atcoder::dsu m_dsu;
::std::vector<int> m_out;
::std::vector<int> m_vid2dfs;
::std::vector<int> m_dfs2vid;
::std::vector<int> m_eid2dfs;
::std::vector<int> m_dfs2eid;
::std::vector<::std::vector<int>> m_ancestors;
public:
class vchildren_view : public ::std::ranges::view_interface<vchildren_view> {
::tools::hld const *m_parent;
int m_v;
public:
class iterator {
private:
::tools::hld const *m_parent;
int m_v;
int m_i;
public:
using difference_type = ::std::ptrdiff_t;
using value_type = int;
using reference = int;
using pointer = int*;
using iterator_category = ::std::input_iterator_tag;
iterator() = default;
iterator(::tools::hld const * const parent, const int v, const int i) :
m_parent(parent),
m_v(v),
m_i(i) {
}
reference operator*() const {
return this->m_parent->m_edges[this->m_parent->m_graph[this->m_v][this->m_i]] ^ this->m_v;
}
iterator& operator++() {
++this->m_i;
return *this;
}
iterator operator++(int) {
const auto self = *this;
++*this;
return self;
}
friend bool operator==(const iterator& lhs, const iterator& rhs) {
return lhs.m_parent == rhs.m_parent && lhs.m_v == rhs.m_v && lhs.m_i == rhs.m_i;
}
friend bool operator!=(const iterator& lhs, const iterator& rhs) {
return !(lhs == rhs);
}
};
vchildren_view() = default;
vchildren_view(::tools::hld const * const parent, const int v) :
m_parent(parent),
m_v(v) {
}
iterator begin() const {
return iterator(this->m_parent, this->m_v, 0);
};
iterator end() const {
return iterator(this->m_parent, this->m_v, this->m_parent->m_graph[this->m_v].size());
}
};
hld() = default;
explicit hld(const int n) : m_built(false), m_graph(n) {
assert(n >= 1);
}
int size() const {
return this->m_graph.size();
}
void add_edge(const int u, const int v) {
assert(!this->m_built);
assert(0 <= u && u < this->size());
assert(0 <= v && v < this->size());
this->m_graph[u].push_back(this->m_edges.size());
this->m_graph[v].push_back(this->m_edges.size());
this->m_edges.push_back(u ^ v);
}
void build(const int root) {
assert(!this->m_built);
assert(0 <= root && root < this->size());
assert(::std::ssize(this->m_edges) + 1 == this->size());
this->m_parent.resize(this->size());
this->m_depth.resize(this->size());
this->m_dsu = ::atcoder::dsu(this->size());
this->m_out.resize(this->size());
this->m_vid2dfs.resize(this->size());
this->m_dfs2vid.resize(this->size());
this->m_eid2dfs.resize(this->m_edges.size());
this->m_dfs2eid.resize(this->m_edges.size());
::std::vector<int> subtree_size(this->size());
this->m_parent[root] = ::std::numeric_limits<int>::max();
this->m_depth[root] = 0;
::std::stack<::std::pair<int, bool>> stack;
stack.emplace(root, false);
stack.emplace(root, true);
while (!stack.empty()) {
const auto [here, pre] = stack.top();
stack.pop();
if (pre) {
for (const auto eid : this->m_graph[here]) {
const auto next = this->m_edges[eid] ^ here;
if (here == root || next != (this->m_edges[this->m_parent[here]] ^ here)) {
this->m_parent[next] = eid;
this->m_depth[next] = this->m_depth[here] + 1;
stack.emplace(next, false);
stack.emplace(next, true);
}
}
} else {
subtree_size[here] = 1;
for (const auto eid : this->m_graph[here]) {
const auto child = this->m_edges[eid] ^ here;
if (here == root || child != (this->m_edges[this->m_parent[here]] ^ here)) {
subtree_size[here] += subtree_size[child];
}
}
}
}
for (int v = 0; v < this->size(); ++v) {
if (v != root) {
this->m_graph[v].erase(::std::ranges::find(this->m_graph[v], this->m_parent[v]));
}
if (this->m_graph[v].size() > 1) {
::std::iter_swap(
this->m_graph[v].begin(),
::std::ranges::max_element(
this->m_graph[v],
::tools::less_by([&](const int eid) { return subtree_size[this->m_edges[eid] ^ v]; })
)
);
}
}
int dfs_order = 0;
stack.emplace(root, false);
stack.emplace(root, true);
while (!stack.empty()) {
const auto [here, pre] = stack.top();
stack.pop();
if (pre) {
this->m_vid2dfs[here] = dfs_order;
this->m_dfs2vid[dfs_order] = here;
if (here != root) {
this->m_eid2dfs[this->m_parent[here]] = dfs_order - 1;
this->m_dfs2eid[dfs_order - 1] = this->m_parent[here];
}
++dfs_order;
if (!this->m_graph[here].empty()) {
this->m_dsu.merge(here, this->m_edges[this->m_graph[here].front()] ^ here);
}
for (auto it = this->m_graph[here].rbegin(); it != this->m_graph[here].rend(); ++it) {
stack.emplace(this->m_edges[*it] ^ here, false);
stack.emplace(this->m_edges[*it] ^ here, true);
}
} else {
this->m_out[here] = dfs_order;
}
}
this->m_built = true;
}
int depth(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return this->m_depth[v];
}
int vparent(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
assert(this->m_depth[v] > 0);
return this->m_edges[this->m_parent[v]] ^ v;
}
int eparent(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
assert(this->m_depth[v] > 0);
return this->m_parent[v];
}
int vancestor(const int v, const int k) {
assert(this->m_built);
assert(0 <= v && v < this->size());
assert(0 <= k && k <= this->m_depth[v]);
if (this->m_ancestors.empty()) {
this->m_ancestors.resize(this->size());
::std::vector<int> targets(this->size());
::std::iota(targets.begin(), targets.end(), 0);
targets.erase(::std::remove(targets.begin(), targets.end(), this->m_dfs2vid[0]), targets.end());
for (const auto t : targets) {
this->m_ancestors[t].push_back(this->vparent(t));
}
for (int g = 1; [&]() {
targets.erase(::std::remove_if(targets.begin(), targets.end(), [&](const int t) {
return this->m_depth[t] < ::tools::pow2(g);
}), targets.end());
return !targets.empty();
}(); ++g) {
for (const auto t : targets) {
this->m_ancestors[t].push_back(this->m_ancestors[this->m_ancestors[t][g - 1]][g - 1]);
}
}
}
int res = v;
for (int g = 0; ::tools::pow2(g) <= k; ++g) {
if ((k >> g) & 1) {
res = this->m_ancestors[res][g];
}
}
return res;
}
::tools::hld::vchildren_view vchildren(const int v) const & {
assert(this->m_built);
assert(0 <= v && v < this->size());
return ::tools::hld::vchildren_view(this, v);
}
const ::std::vector<int>& echildren(const int v) const & {
assert(this->m_built);
assert(0 <= v && v < this->size());
return this->m_graph[v];
}
int vid2dfs(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return this->m_vid2dfs[v];
}
int dfs2vid(const int i) const {
assert(this->m_built);
assert(0 <= i && i < this->size());
return this->m_dfs2vid[i];
}
int eid2dfs(const int e) const {
assert(this->m_built);
assert(0 <= e && e < this->size());
return this->m_eid2dfs[e];
}
int dfs2eid(const int i) const {
assert(this->m_built);
assert(0 <= i && i < this->size());
return this->m_dfs2eid[i];
}
int lca(int u, int v) {
assert(this->m_built);
assert(0 <= u && u < this->size());
assert(0 <= v && v < this->size());
while (!this->m_dsu.same(u, v)) {
if (this->m_depth[this->m_dsu.leader(u)] >= this->m_depth[this->m_dsu.leader(v)]) {
u = this->m_edges[this->m_parent[this->m_dsu.leader(u)]] ^ this->m_dsu.leader(u);
} else {
v = this->m_edges[this->m_parent[this->m_dsu.leader(v)]] ^ this->m_dsu.leader(v);
}
}
if (this->m_depth[u] >= this->m_depth[v]) {
return v;
} else {
return u;
}
}
::std::pair<int, int> vsubtree(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return ::std::make_pair(this->m_vid2dfs[v], this->m_out[v]);
}
::std::pair<int, int> esubtree(const int v) const {
assert(this->m_built);
assert(0 <= v && v < this->size());
return ::std::make_pair(this->m_depth[v] == 0 ? 0 : this->m_eid2dfs[this->m_parent[v]] + 1, this->m_out[v] - 1);
}
::std::vector<::std::pair<int, int>> vpath(int u, int v) {
assert(this->m_built);
assert(0 <= u && u < this->size());
assert(0 <= v && v < this->size());
::std::vector<::std::pair<int, int>> head, tail;
while (!this->m_dsu.same(u, v)) {
if (this->m_depth[this->m_dsu.leader(u)] >= this->m_depth[this->m_dsu.leader(v)]) {
head.emplace_back(this->m_vid2dfs[u] + 1, this->m_vid2dfs[this->m_dsu.leader(u)]);
u = this->m_edges[this->m_parent[this->m_dsu.leader(u)]] ^ this->m_dsu.leader(u);
} else {
tail.emplace_back(this->m_vid2dfs[this->m_dsu.leader(v)], this->m_vid2dfs[v] + 1);
v = this->m_edges[this->m_parent[this->m_dsu.leader(v)]] ^ this->m_dsu.leader(v);
}
}
if (this->m_depth[u] >= this->m_depth[v]) {
head.emplace_back(this->m_vid2dfs[u] + 1, this->m_vid2dfs[v]);
} else {
head.emplace_back(this->m_vid2dfs[u], this->m_vid2dfs[v] + 1);
}
::std::copy(tail.rbegin(), tail.rend(), ::std::back_inserter(head));
return head;
}
::std::vector<::std::pair<int, int>> epath(int u, int v) {
assert(this->m_built);
assert(0 <= u && u < this->size());
assert(0 <= v && v < this->size());
::std::vector<::std::pair<int, int>> head, tail;
while (!this->m_dsu.same(u, v)) {
if (this->m_depth[this->m_dsu.leader(u)] >= this->m_depth[this->m_dsu.leader(v)]) {
head.emplace_back(this->m_eid2dfs[this->m_parent[u]] + 1, this->m_eid2dfs[this->m_parent[this->m_dsu.leader(u)]]);
u = this->m_edges[this->m_parent[this->m_dsu.leader(u)]] ^ this->m_dsu.leader(u);
} else {
tail.emplace_back(this->m_eid2dfs[this->m_parent[this->m_dsu.leader(v)]], this->m_eid2dfs[this->m_parent[v]] + 1);
v = this->m_edges[this->m_parent[this->m_dsu.leader(v)]] ^ this->m_dsu.leader(v);
}
}
if (this->m_depth[u] > this->m_depth[v]) {
head.emplace_back(this->m_eid2dfs[this->m_parent[u]] + 1, this->m_eid2dfs[this->m_graph[v].front()]);
} else if (this->m_depth[u] < this->m_depth[v]) {
head.emplace_back(this->m_eid2dfs[this->m_graph[u].front()], this->m_eid2dfs[this->m_parent[v]] + 1);
}
::std::copy(tail.rbegin(), tail.rend(), ::std::back_inserter(head));
return head;
}
};
}
#line 7 "tests/hld/vsubtree.test.cpp"
using ll = long long;
int main() {
std::cin.tie(nullptr);
std::ios_base::sync_with_stdio(false);
ll N, Q;
std::cin >> N >> Q;
std::vector<ll> a(N);
for (auto& a_i : a) std::cin >> a_i;
tools::hld hld(N);
for (ll v = 1; v < N; ++v) {
ll p;
std::cin >> p;
hld.add_edge(p, v);
}
hld.build(0);
atcoder::fenwick_tree<ll> fw(N);
for (ll v = 0; v < N; ++v) {
fw.add(hld.vid2dfs(v), a[v]);
}
for (ll q = 0; q < Q; ++q) {
ll t;
std::cin >> t;
if (t == 0) {
ll u, x;
std::cin >> u >> x;
fw.add(hld.vid2dfs(u), x);
} else {
ll u;
std::cin >> u;
const auto& [l, r] = hld.vsubtree(u);
std::cout << fw.sum(l, r) << '\n';
}
}
return 0;
}
Env | Name | Status | Elapsed | Memory |
---|---|---|---|---|
g++ | example_00 |
![]() |
5 ms | 4 MB |
g++ | line_00 |
![]() |
231 ms | 60 MB |
g++ | line_01 |
![]() |
233 ms | 60 MB |
g++ | max_random_00 |
![]() |
472 ms | 57 MB |
g++ | max_random_01 |
![]() |
453 ms | 57 MB |
g++ | max_random_02 |
![]() |
448 ms | 57 MB |
g++ | random_00 |
![]() |
318 ms | 45 MB |
g++ | random_01 |
![]() |
402 ms | 53 MB |
g++ | random_02 |
![]() |
95 ms | 9 MB |
g++ | random_03 |
![]() |
278 ms | 49 MB |
g++ | random_04 |
![]() |
173 ms | 33 MB |
g++ | small_00 |
![]() |
5 ms | 4 MB |
g++ | small_01 |
![]() |
4 ms | 4 MB |
g++ | small_02 |
![]() |
4 ms | 4 MB |
g++ | small_03 |
![]() |
5 ms | 4 MB |
g++ | small_04 |
![]() |
4 ms | 4 MB |