AcWing 1073 树的中心 树形dp (详解)
这道题目非常有新意,在过去,我们通常先访问子节点去更新父节点的状态,但是这道题我们还需要从父节点去更新子节点。
我们可以想象为向上和向下两个方向,我们任取一点,先向下走,再回来更新上面的点,这样我们就能得出向下的最长距离和次长距离,同时记录最长距离是走哪个点获得的。
然后我们再次深搜,对每个点用这个点去更新他所有子节点,因为他的子节点的最大向上值就是他的最大向上值或者向下最长距离或者次长距离加上这两点间的距离。
代码
#include <bits/stdc++.h>using namespace std;const int N = 100010, INF = 0x3f3f3f3f;int n, res = INF;int h[N], e[N], ne[N], w[N], idx;int d1[N], d2[N], s[N], up[N];void add(int a, int b, int c)
{e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}void dfs1(int u, int f)
{for (int i = h[u]; i != -1; i = ne[i]){int j = e[i];if (j == f) continue;dfs1(j, u);if (d1[j] + w[i] >= d1[u]){s[u] = j;d2[u] = d1[u];d1[u] = d1[j] + w[i];}else if (d1[j] + w[i] >= d2[u]){d2[u] = d1[j] + w[i];}}
}void dfs2(int u, int f)
{for (int i = h[u]; i != -1; i = ne[i]){int j = e[i];if (j == f) continue;if (s[u] == j) up[j] = w[i] + max(up[u], d2[u]);else up[j] = w[i] + max(up[u], d1[u]);dfs2(j, u);}
}int main()
{cin >> n;memset(h, -1, sizeof h);for (int i = 1; i < n; i ++ ){int a, b, c;cin >> a >> b >> c;add(a, b, c), add(b, a, c);}dfs1(1, -1);dfs2(1, -1);for (int i = 1; i <= n; i ++ ) res = min(res, max(up[i], d1[i]));cout << res << endl;return 0;
}