题意:给你一棵n个节点的树,问对于每一个点离它最远的点距离是多少
分析:对于每一个节点e[i].to来说,它的最远距离可能来自它的子树,或者它的父亲节点son想到这里,你离AC这道题就不远了!
具体实现:
为了完成操作,我们需要两次DFS
DFS1:
首先我们先以1号节点为根节点将树遍历一遍(从下到上),并且把每一个节点在它子树中(向下延伸)的最长距离和第二长保存下来,同时保存是从哪一个子节点获得的最大值(为什么不保存第二大的值是从哪里获得的呢?稍后讲解)。
DFS2:
然后我们从根节点(其实就是1号结点)开始,向下遍历,对于每个节点son(不要被单词迷惑了)的儿子e[i].to进行更新:
如果come[son]=e[i].to即son的最长距离不是由e[i].to更新:
f[e[i].to]=max(f[e[i].to],e[i].w+f[son]);
f
[
e
[
i
]
.
t
o
]
=
m
a
x
(
f
[
e
[
i
]
.
t
o
]
,
e
[
i
]
.
w
+
f
[
s
o
n
]
)
;
如果come[son]=e[i].to即son的最长距离是由e[i].to更新:
f[e[i].to]=max(f[e[i].to],e[i].w+g[son]);
f
[
e
[
i
]
.
t
o
]
=
m
a
x
(
f
[
e
[
i
]
.
t
o
]
,
e
[
i
]
.
w
+
g
[
s
o
n
]
)
;
记得在更新时将g[e[i].to]同时更新了!
这就是为什么我们不需要存储第二长距离来自哪里的原因了(反正不能用第一就肯定能用第二,能用第一还看什么第二…)
注意!若e[i].to能从son继承到的值与e[i].to从子节点处获得的最长距离(也就是f[e[i].to])相等,那么我们是需要更新的!,因为这样对于come[e[i].to]来说就能够继承到e[i].to的最长距离了!
#include<bits/stdc++.h>
using namespace std;
const int maxn=10010;
int f[maxn],g[maxn],come[maxn];//f[]:最长距离 g[]:第二长距离 come[]:从哪里获得最大值
int cnt=0;
int head[maxn];
struct node{
int w,next,to;
}e[2*maxn];
void addedge(int x,int y,int z) {
e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; e[cnt].w=z;
e[++cnt].to=x; e[cnt].next=head[y]; head[y]=cnt; e[cnt].w=z;
}
void work1(int son,int father) {//第一遍DFS
for(int i=head[son];i;i=e[i].next) {
if(e[i].to==father) continue;
work1(e[i].to,son);
if(f[e[i].to]+e[i].w>f[son]) {
come[son]=e[i].to;
g[son]=f[son];
f[son]=f[e[i].to]+e[i].w;
}else {
g[son]=max(g[son],f[e[i].to]+e[i].w);
}
}
return ;
}
void work2(int son,int father) {//第二遍DFS
for(int i=head[son];i;i=e[i].next) {
if(e[i].to==father) continue;
if(come[son]!=e[i].to) {//如果f[son]不是从e[i].to继承来的即come[son]!=e[i].to
if(e[i].w+f[son]>=f[e[i].to]) {
come[e[i].to]=son;
g[e[i].to]=f[e[i].to];//记得更新g[]
f[e[i].to]=e[i].w+f[son];
} else{
g[e[i].to]=max(g[e[i].to],e[i].w+f[son]);
}
} else {//如果f[son]是从e[i].to继承来的即come[son]==e[i].to
if(e[i].w+g[son]>=f[e[i].to]) {
come[e[i].to]=son;
g[e[i].to]=f[e[i].to];
f[e[i].to]=e[i].w+g[son];
} else {
g[e[i].to]=max(g[e[i].to],e[i].w+g[son]);
}
}
work2(e[i].to,son);
}
}
int main() {
int n;
while(~scanf("%d",&n)) {
memset(head,0,sizeof(head));
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
memset(come,0,sizeof(come));
memset(e,0,sizeof(e));
cnt=0;
int y,z;
for(int x=2;x<=n;x++) {
scanf("%d%d",&y,&z);
addedge(x,y,z);
}
work1(1,0);
work2(1,0);
for(int i=1;i<=n;i++)
printf("%d\n",f[i]);
}
return 0;
}
by:Chlience