和LightOJ1257一样,之前我用了树分治写了。其实原来这题是道经典的树形DP,感觉这个DP不简单。。
- dp[0][u]表示以u为根的子树中的结点与u的最远距离
- dp[1][u]表示以u为根的子树中的结点与u的次远距离
这两个可以一遍dfs通过儿子结点转移得到。显然dp[0][u]就是u的一个可能的答案,即u往下走的最远距离,还缺一部分就是u往上走的最远距离:
- dp[2][u]表示u往上走的最远距离
对于这个的转移,分两种情况,是这样的:
- dp[2][v] = max( dp[0][u]+weight(u,v) , dp[2][u]+weight(u,v) ) (v是u的儿子 且 u往下走的最远距离不经过v)
- dp[2][v] = max( dp[1][u]+weight(u,v) , dp[2][u]+weight(u,v) ) (v是u的儿子 且 u往下走的最远距离经过v)
再一遍dfs就能得到。每个u的答案就是max(dp[0][u],dp[2][u]);
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define MAXN 11111 6 struct Edge{ 7 int v,w,next; 8 }edge[MAXN<<1]; 9 int NE,head[MAXN]; 10 void addEdge(int u,int v,int w){ 11 edge[NE].v=v; edge[NE].w=w; 12 edge[NE].next=head[u]; head[u]=NE++; 13 } 14 long long d[3][MAXN]; 15 int idx[MAXN]; 16 void dfs0(int u,int fa){ 17 long long mx0=0,mx1=0; 18 for(int i=head[u]; i!=-1; i=edge[i].next){ 19 int v=edge[i].v; 20 if(v==fa) continue; 21 dfs0(v,u); 22 if(mx0<=d[0][v]+edge[i].w) mx1=mx0,mx0=d[0][v]+edge[i].w,idx[u]=v; 23 else if(mx1<d[0][v]+edge[i].w) mx1=d[0][v]+edge[i].w; 24 else if(mx1<d[1][v]+edge[i].w) mx1=d[1][v]+edge[i].w; 25 } 26 d[0][u]=mx0; d[1][u]=mx1; 27 } 28 void dfs1(int u,int fa){ 29 for(int i=head[u]; i!=-1; i=edge[i].next){ 30 int v=edge[i].v; 31 if(v==fa) continue; 32 if(idx[u]==v) d[2][v]=max(d[1][u]+edge[i].w,d[2][u]+edge[i].w); 33 else d[2][v]=max(d[0][u]+edge[i].w,d[2][u]+edge[i].w); 34 dfs1(v,u); 35 } 36 } 37 int main(){ 38 int n,a,b; 39 while(~scanf("%d",&n)){ 40 NE=0; 41 memset(head,-1,sizeof(head)); 42 for(int i=2; i<=n; ++i){ 43 scanf("%d%d",&a,&b); 44 addEdge(i,a,b); addEdge(a,i,b); 45 } 46 memset(d,0,sizeof(d)); 47 dfs0(1,1); 48 dfs1(1,1); 49 for(int i=1; i<=n; ++i){ 50 printf("%lld ",max(d[0][i],d[2][i])); 51 } 52 } 53 return 0; 54 }