F. A Growing Tree
F. A Growing Tree
You are given a rooted tree with the root at vertex , initially consisting of a single vertex. Each vertex has a numerical value, initially set to . There are also queries of two types:
- The first type: add a child vertex with the number to vertex , where is the current size of the tree. The numerical value of the new vertex will be .
- The second type: add to the numerical values of all vertices in the subtree of vertex .
After all queries, output the numerical value of all of the vertices in the final tree.
Input
The first line contains a single integer () — the number of test cases. The descriptions of the test cases follow.
The first line of each test case contains a single integer () — the number of queries.
The following lines can fall into two cases:
- The first type of query: The -th line contains two integers (), . You need to add a child with the number to vertex , where is the current size of the tree. It is guaranteed that .
- The second type of query: The -th line contains three integers (), , (). You need to add to all numerical values of vertices in the subtree of . It is guaranteed that , where is the current size of the tree.
It is guaranteed that the sum of across all test cases does not exceed .
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 序,这样给以 为根的子树都加上 等价于给区间 都加上 ,区间加上某个数可以用树状数组维护差分数组来实现。
因此在建完树后依次此枚举每个询问,如果是第二个操作则直接在子树对应的 dfs 序上加上一个数。如果是第一个操作则把该节点对应的值清为 即可,相当于消除在还没插入该节点前其祖先对该节点的影响。实现的话只需查询该节点此时对应的值,然后加上这个值的相反数即可。
AC 代码如下,时间复杂度为 :
#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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效