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 (1T104) — the number of test cases. The descriptions of the test cases follow.

The first line of each test case contains a single integer q (1q5105) — 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 ti (ti=1), vi. You need to add a child with the number sz+1 to vertex vi, where sz is the current size of the tree. It is guaranteed that 1visz.
  • The second type of query: The i-th line contains three integers ti (ti=2), vi, xi (109xi109). You need to add xi to all numerical values of vertices in the subtree of vi. It is guaranteed that 1visz, where sz is the current size of the tree.

It is guaranteed that the sum of q across all test cases does not exceed 5105.

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 等价于给区间 [tinu,toutu] 都加上 c,区间加上某个数可以用树状数组维护差分数组来实现。

  因此在建完树后依次此枚举每个询问,如果是第二个操作则直接在子树对应的 dfs 序上加上一个数。如果是第一个操作则把该节点对应的值清为 0 即可,相当于消除在还没插入该节点前其祖先对该节点的影响。实现的话只需查询该节点此时对应的值,然后加上这个值的相反数即可。

  AC 代码如下,时间复杂度为 O(qlogq)

#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

posted @   onlyblues  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示