链接
题目描述
给出一颗以1为根的树,求每个点到树上离这个点最远的点之间的距离
样例输入
5
1 1
2 1
3 1
1 1
样例输出
3
2
3
4
4
思路
用树形DP
对于一个点,离它最远的点无非就两个位置,一个在它正下方(子树内,另一种情况就是在它某个祖先的子树内
设
f
x
,
012
f_{x,{012}}
fx,012表示处理到x这个点的情况
0为到子树内的某个点,使得距离最大
1为次大
2为向上的最大距离
那就直接模拟
然后对于一个点y,如果它是它父亲的最大距离点,那就用
m
a
x
(
f
x
,
1
+
d
i
s
x
,
y
,
f
x
,
2
+
d
i
s
x
,
y
)
max(f_{x,1} + dis_{x,y}, f_{x,2} + dis_{x,y})
max(fx,1+disx,y,fx,2+disx,y)就是先向上再向下或是直接一路向上
如果不是最大距离点
则
m
a
x
(
f
x
,
0
+
d
i
s
x
,
y
,
f
x
,
2
+
d
i
s
x
,
y
)
max(f_{x,0} + dis_{x,y}, f_{x,2} + dis_{x,y})
max(fx,0+disx,y,fx,2+disx,y)
下面代码用
i
d
x
i
idx_i
idxi表示i的最大距离点
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
struct node
{
int to, next, val;
}g[100001];
int n, t;
int h[10001], idx[10001];
ll f[10001][3];
void add(int x, int y, int val)
{
g[++t] = (node){y, h[x], val}; h[x] = t;
}
void dp1(int x, int fa)
{
ll r1=0, r2=0;
for(int i = h[x]; i; i = g[i].next)
{
int w = g[i].val;
int to = g[i].to;
if(to == fa) continue;
dp1(to, x);
if(r1 < f[to][0] + w * 1ll){
r2 = r1;
r1 = f[to][0] + w * 1ll;
idx[x] = to;
}//相等也可以更新次大
else if(r2 < f[to][0] + w * 1ll)
r2 = f[to][0] + w * 1ll;
}
f[x][0] = r1;
f[x][1] = r2;
}
void dp2(int x, int fa)
{
for(int i = h[x]; i; i = g[i].next)
{
int w = g[i].val;
int to = g[i].to;
if(to == fa) continue;
if(idx[x] == to) f[to][2] = max(f[x][1], f[x][2]) + w * 1ll;
else f[to][2] = max(f[x][0], f[x][2]) + w * 1ll;
dp2(to, x);
}
}
int main()
{
int x; int y;
while(scanf("%d", &n) != EOF) {
t = 0;
memset(h, 0, sizeof(h));
memset(idx, 0, sizeof(idx));
memset(f, 0, sizeof(f));
for(int i = 2; i <= n; ++i)
{
scanf("%d%d", &x, &y);
add(x, i, y);
add(i, x, y);
}
dp1(1, 0);//求出012
dp2(1, 0);//求答案
for(int i = 1; i <= n; ++i)
printf("%lld\n", max(f[i][0], f[i][2]));
}
return 0;
}