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

posted @ 2023-11-22 15:04  onlyblues  阅读(8)  评论(0编辑  收藏  举报
Web Analytics