F. A Growing Tree
看到给子树加和是很容易想到树链剖分的。
这题表面上往树上动态加点,容易让我们觉得直接往子树上加权值会影响还未添加进来的点。
但是我们再仔细考虑一下,实际上当每一个点新加进来的时候,这个点的子树的值都相等,因此每次插入一个新点的时候给这个节点的子树减掉当前的值就相当于新插入一个点了。
由于这题是区间修改单点查询,所以实际上可以用树状数组来差分。
当然也可以使用带懒标记的线段树。
#include <bits/stdc++.h>
using i64 = long long;
struct HLD {
int n;
std::vector<int> siz, top, dep, parent, in, out, seq;
std::vector<std::vector<int>> adj;
int cur;
HLD() {}
HLD(int n) {
init(n);
}
void init(int n) {
this->n = n;
siz.resize(n);
top.resize(n);
dep.resize(n);
parent.resize(n);
in.resize(n);
out.resize(n);
seq.resize(n);
cur = 0;
adj.assign(n, {});
}
void addEdge(int u, int v) {
adj[u].push_back(v);
adj[v].push_back(u);
}
void work(int root = 0) {
top[root] = root;
dep[root] = 0;
parent[root] = -1;
dfs1(root);
dfs2(root);
}
void dfs1(int u) {
if (parent[u] != -1) {
adj[u].erase(std::find(adj[u].begin(), adj[u].end(), parent[u]));
}
siz[u] = 1;
for (auto &v : adj[u]) {
parent[v] = u;
dep[v] = dep[u] + 1;
dfs1(v);
siz[u] += siz[v];
if (siz[v] > siz[adj[u][0]]) {
std::swap(v, adj[u][0]);
}
}
}
void dfs2(int u) {
in[u] = cur++;
seq[in[u]] = u;
for (auto v : adj[u]) {
top[v] = v == adj[u][0] ? top[u] : v;
dfs2(v);
}
out[u] = cur;
}
int lca(int u, int v) {
while (top[u] != top[v]) {
if (dep[top[u]] > dep[top[v]]) {
u = parent[top[u]];
} else {
v = parent[top[v]];
}
}
return dep[u] < dep[v] ? u : v;
}
int dist(int u, int v) {
return dep[u] + dep[v] - 2 * dep[lca(u, v)];
}
int jump(int u, int k) {
if (dep[u] < k) {
return -1;
}
int d = dep[u] - k;
while (dep[top[u]] > d) {
u = parent[top[u]];
}
return seq[in[u] - dep[u] + d];
}
bool isAncester(int u, int v) {
return in[u] <= in[v] && in[v] < out[u];
}
int rootedParent(int u, int v) {
std::swap(u, v);
if (u == v) {
return u;
}
if (!isAncester(u, v)) {
return parent[u];
}
auto it = std::upper_bound(adj[u].begin(), adj[u].end(), v, [&](int x, int y) {
return in[x] < in[y];
}) - 1;
return *it;
}
int rootedSize(int u, int v) {
if (u == v) {
return n;
}
if (!isAncester(v, u)) {
return siz[v];
}
return n - siz[rootedParent(u, v)];
}
int rootedLca(int a, int b, int c) {
return lca(a, b) ^ lca(b, c) ^ lca(c, a);
}
};
template <typename T>
struct Fenwick {
int n;
std::vector<T> a;
Fenwick(int n = 0) {
init(n);
}
void init(int n) {
this->n = n;
a.assign(n, T());
}
void add(int x, T v) {
for (int i = x + 1; i <= n; i += i & -i) {
a[i - 1] += v;
}
}
T sum(int x) {
auto ans = T();
for (int i = x; i > 0; i -= i & -i) {
ans += a[i - 1];
}
return ans;
}
T rangeSum(int l, int r) {
return sum(r) - sum(l);
}
int kth(T k) {
int x = 0;
for (int i = 1 << std::__lg(n); i; i /= 2) {
if (x + i <= n && k >= a[x + i - 1]) {
x += i;
k -= a[x - 1];
}
}
return x;
}
};
struct Qry {
int op, v, x;
};
void solve() {
int n;
std::cin >> n;
int idx = 1;
std::vector<Qry> op(n);
for (int i = 0; i < n; i++) {
int ins, v, x;
std::cin >> ins >> v;
v--;
if (ins == 1) {
op[i] = {ins, v, idx++};
} else {
int x;
std::cin >> x;
op[i] = {ins, v, x};
}
}
HLD t(idx);
for (auto [ins, v, x] : op) {
// std::cerr << "instruction: " << ins << " " << v << " " << x << "\n";
if (ins == 1) {
// std::cerr << "vertex: " << v << " " << x << "\n";
t.addEdge(v, x);
}
}
Fenwick<i64> fen(idx);
t.work();
for (auto [ins, v, x] : op) {
if (ins == 1) {
// i64 val = seg.rangeQuery(t.in[x], t.in[x] + 1).x;
i64 val = fen.sum(t.in[x] + 1);
// std::cerr << val << "\n";
fen.add(t.in[x], -val);
fen.add(t.out[x], val);
// seg.rangeApply(t.in[x], t.out[x], {-val});
} else {
fen.add(t.in[v], x);
fen.add(t.out[v], -x);
// seg.rangeApply(t.in[v], t.out[v], {x});
}
}
for (int i = 0; i < idx; i++) {
std::cout << fen.sum(t.in[i] + 1) << " \n"[i == idx - 1];
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}