F. A Growing Tree
F. A Growing Tree
You are given a rooted tree with the root at vertex $1$, initially consisting of a single vertex. Each vertex has a numerical value, initially set to $0$. There are also $q$ queries of two types:
- The first type: add a child vertex with the number $sz + 1$ to vertex $v$, where $sz$ is the current size of the tree. The numerical value of the new vertex will be $0$.
- The second type: add $x$ to the numerical values of all vertices in the subtree of vertex $v$.
After all queries, output the numerical value of all of the vertices in the final tree.
Input
The first line contains a single integer $T$ ($1 \leq T \leq 10^4$) — the number of test cases. The descriptions of the test cases follow.
The first line of each test case contains a single integer $q$ ($1 \leq q \leq 5 \cdot 10^5$) — the number of queries.
The following $q$ lines can fall into two cases:
- The first type of query: The $i$-th line contains two integers $t_i$ ($t_i = 1$), $v_i$. You need to add a child with the number $sz + 1$ to vertex $v_i$, where $sz$ is the current size of the tree. It is guaranteed that $1 \leq v_i \leq sz$.
- The second type of query: The $i$-th line contains three integers $t_i$ ($t_i = 2$), $v_i$, $x_i$ ($-10^9 \leq x_i \leq 10^9$). You need to add $x_i$ to all numerical values of vertices in the subtree of $v_i$. It is guaranteed that $1 \leq v_i \leq sz$, where $sz$ is the current size of the tree.
It is guaranteed that the sum of $q$ across all test cases does not exceed $5 \cdot 10^5$.
Output
For each test case, output the numerical value of each vertex of the final tree after all queries have been performed.
Example
input
3
9
2 1 3
1 1
2 2 1
1 1
2 3 2
1 3
2 1 4
1 3
2 3 2
5
2 1 1
1 1
2 1 -1
1 1
2 1 1
5
1 1
1 1
2 1 1
2 1 3
2 2 10
output
7 5 8 6 2
1 0 1
4 14 4
Note
In the first case, the final tree with the assigned numerical values will look like this:
The final tree with the assigned numerical values
解题思路
当时没学过 dfs 序 所以不会做。
考虑离线处理询问,先把树给建出来。其中由于第二个操作是给某个子树都加上一个数,因此考虑求出这棵树的 dfs 序,这样给以 $u$ 为根的子树都加上 $c$ 等价于给区间 $[ \text{tin}_u, \, \text{tout}_u ]$ 都加上 $c$,区间加上某个数可以用树状数组维护差分数组来实现。
因此在建完树后依次此枚举每个询问,如果是第二个操作则直接在子树对应的 dfs 序上加上一个数。如果是第一个操作则把该节点对应的值清为 $0$ 即可,相当于消除在还没插入该节点前其祖先对该节点的影响。实现的话只需查询该节点此时对应的值,然后加上这个值的相反数即可。
AC 代码如下,时间复杂度为 $O(q \log{q})$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5e5 + 10;
int n, m;
int head[N], e[N], ne[N], idx;
int tin[N], tout[N], sz;
LL tr[N];
struct Node {
int x, y, z;
}q[N];
void add(int u, int v) {
e[idx] = v, ne[idx] = head[u], head[u] = idx++;
}
void dfs(int u) {
tin[u] = ++sz;
for (int i = head[u]; i != -1; i = ne[i]) {
dfs(e[i]);
}
tout[u] = sz;
}
int lowbit(int x) {
return x & -x;
}
void modify(int x, LL c) {
for (int i = x; i <= n; i += lowbit(i)) {
tr[i] += c;
}
}
LL query(int x) {
LL ret = 0;
for (int i = x; i; i -= lowbit(i)) {
ret += tr[i];
}
return ret;
}
void solve() {
scanf("%d", &m);
memset(head, -1, m + 10 << 2);
idx = 0, n = 1;
for (int i = 0; i < m; i++) {
scanf("%d %d", &q[i].x, &q[i].y);
if (q[i].x == 2) scanf("%d", &q[i].z);
else add(q[i].y, ++n), q[i].y = n;
}
sz = 0;
memset(tr, 0, n + 10 << 3);
dfs(1);
for (int i = 0; i < m; i++) {
if (q[i].x == 1) {
LL t = query(tin[q[i].y]);
modify(tin[q[i].y], -t);
modify(tout[q[i].y] + 1, t);
}
else {
modify(tin[q[i].y], q[i].z);
modify(tout[q[i].y] + 1, -q[i].z);
}
}
for (int i = 1; i <= n; i++) {
printf("%lld ", query(tin[i]));
}
printf("\n");
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
参考资料
Codeforces Round 907 (Div. 2) Editorial:https://codeforces.com/blog/entry/121876
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17849055.html