题解:P10962 Computer
题目传送门
题意
给定一棵有
思路
-
暴力:以每个点为起点依次进行
dfs(i, 0),查看从i 出发最多走多少步。 -
二次 dfs 法:第一次 dfs 从下往上搜,第二次 dfs 从上往下搜,具体见代码。
ACcode:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e4 + 5;
vector<pair<int, int> > g[N];
int dis1[N], dis2[N]; //dis1表示子树的最长路, dis2表示子树的次长路
int f[N], son[N]; //son表示子树的最长路的节点编号, f表示子树外的最长路
int n;
void dfs1(int u, int fa)
{
for (auto x : g[u])
{
int v = x.first, w = x.second;
if (v == fa)
continue;
dfs1(v, u);
//回溯过程将子树的信息带回来更新u
if (dis1[u] < dis1[v] + w)
{
dis2[u] = dis1[u]; //先更新次长路
dis1[u] = dis1[v] + w;
son[u] = v; // 最长路先经过v
}
else if (dis2[u] < dis1[v] + w)
dis2[u] = dis1[v] + w;
}
return ;
}
void dfs2(int u, int fa)
{
for (auto x : g[u])
{
int v = x.first, w = x.second;
if (v == fa)
continue;
//在递的过程中更新数据,父亲更新儿子
if (son[u] != v) //u的最长路不包含v, 可以直接用
f[v] = max(dis1[u], f[u]) + w;
else
f[v] = max(dis2[u], f[u]) + w;
dfs2(v, u);
}
return ;
}
void solve()
{
for (int i = 1; i <= n; i++)
g[i].clear();
//多测注意清空
memset(dis1, 0, sizeof dis1);
memset(dis2, 0, sizeof dis2);
memset(f, 0, sizeof f);
for (int i = 2; i <= n; i++)
{
int u, v;
cin >> u >> v;
g[i].push_back({u, v});
g[u].push_back({i, v});
}
dfs1(1, 0); //从下往上dfs
dfs2(1, 0); //从上往下dfs
for (int i = 1; i <= n; i++)
cout << max(dis1[i], f[i]) << "\n";
return ;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
while (cin >> n)
solve();
return 0;
}