英文题干

Note the unusual memory limit for this problem.

Given a rooted tree with n nodes and n-1 edges. The i-th edge can be described by , which represents an edge connecting node and node , where node is the parent of node .

There are n-1 queries. The i-th query contains an integer , asking for the length of the longest simple path starting from node in the graph (forest) formed by the first i edges. It is guaranteed that there does not exist j such that and = , i.e., is the root of a tree in the forest.

Input:

Each test contains multiple test cases. The first line contains the number of test cases . The description of the test cases follows.

The first line of each test case contains an integer , representing the number of nodes in the tree.

The next n−1 lines each contain three integers , representing that the parent of node is , and the i-th query is .

It is guaranteed that: For each test case, the n−1 edges form a rooted tree.

For each test case, for any , there does not exist j such that and =.

The sum of n over all test cases does not exceed .

Output:

For each test case, output n−1 integers in one line. The i-th integer represents your answer to the i-th query.

中文题干

注意这个问题的特殊的内存限制。(131072K,比正常的262144K少一半)

给定一个有 n 个节点和 n-1 条边的根树。第 i 条边可以用描述,表示连接节点和节点的边,其中节点是节点的父节点。

有n-1个查询。第i个查询包含一个整数,询问在由前i条边构成的图(森林)中,从节点开始的最长简单路径的长度。保证不存在 ,使得 = ,即是森林中一棵树的根。

思路

一道维护附加信息的并查集,最开始题目理解错了导致浪费了好多时间qaq (题目输入保证是森林的,说明 一定是某颗树的根,否则 有两个父节点)

  1. 除了基本并查集自带的所属组(group)之外,我们额外维护最长路径和深度两个数组。深度在每次寻根的时候进行累计,节点越往下深度越大。

  2. 由于查询的点只限树根,因此在每次合并的时候要更新树根(a的根节点)的最长路径数组。

AC代码

时间复杂度:O()

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int infmin = 0xc0c0c0c0;
const int infmax = 0x3f3f3f3f;
const int maxn = 1e6 + 10;

ll ans[maxn];  // 节点 i 的最长路径
ll depth[maxn];  // 节点 i 的深度

// 并查集
int group[maxn];
inline int findroot(int x)
{
    if (x != group[x]) {
        int tmp = group[x];
        group[x] = findroot(group[x]);
        depth[x] += depth[tmp];  // 深度累计(越往下值越大)
    }
    return group[x];
}
inline void unite(int x, int y)
{
    int fx = findroot(x);
    int fy = findroot(y);
    if (fx != fy)
    {
        group[fy] = fx;
        depth[y] = depth[x] + 1;
        ans[fx] = max(ans[fx], ans[y] + depth[y]);
    }
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int T;
    cin >> T;

    while (T--) {
        int n;
        cin >> n;

        for (int i = 1; i <= n; i++) {
            group[i] = i;
            depth[i] = 0;
            ans[i] = 0;
        }

        for (int i = 1; i <= n - 1; i++) {
            int u, v, req;
            cin >> u >> v >> req;

            unite(u, v);
            cout << ans[req] << " ";
        }
        cout << "\n";
    }

    return 0;
}