标签:numbers can center 一个 cti most tmp nbsp acm
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 31377 Accepted Submission(s):
4062
树形dp,
dp[u][0] : 以u为根的子树中最远的点是谁
dp[u][1] : 以u为根的子树中次远的点是谁(那么它和dp[u][0]不是一个点)
dp[u][2] : 通过u的父亲到达u的最远的点是谁
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 5 using namespace std; 6 7 const int MAXN = 10010; 8 int dp[MAXN][3]; 9 10 struct Edge{ 11 int to,nxt,w; 12 }e[20010]; 13 int head[20010],tot; 14 15 inline int read() { 16 int x = 0,f = 1;char ch = getchar(); 17 for (; ch<‘0‘||ch>‘9‘; ch = getchar()) 18 if (ch==‘-‘) f = -1; 19 for (; ch>=‘0‘&&ch<=‘9‘; ch = getchar()) 20 x = x*10+ch-‘0‘; 21 return x*f; 22 } 23 24 inline void init() { 25 memset(head,0,sizeof(head)); 26 memset(dp,0,sizeof(dp)); 27 tot = 0; 28 } 29 30 inline void add_edge(int u,int v,int w) { 31 e[++tot].to = v,e[tot].w = w,e[tot].nxt = head[u],head[u] = tot; 32 } 33 34 void dfs1(int u) { 35 for (int i=head[u]; i; i=e[i].nxt) { 36 int v = e[i].to; 37 dfs1(v); // 叶 -> 根 38 int w = e[i].w; 39 int tmp = dp[v][0]+w; 40 if (tmp>=dp[u][0]) { 41 dp[u][1] = dp[u][0]; 42 dp[u][0] = tmp; 43 } 44 else if (tmp>dp[u][1]) { 45 dp[u][1] = tmp; 46 } 47 } 48 } 49 50 void dfs2(int u) { 51 for (int i=head[u]; i; i=e[i].nxt) { 52 int v = e[i].to,w = e[i].w; 53 if (dp[u][0]==dp[v][0]+w) { 54 dp[v][2] = max(dp[u][2],dp[u][1]) + w; 55 } 56 else { 57 dp[v][2] = max(dp[u][2],dp[u][0]) + w; 58 } 59 dfs2(v); // 根 -> 叶 60 } 61 } 62 63 int main() { 64 int n; 65 while (scanf("%d",&n)!=EOF) { 66 init(); 67 for (int a,b,i=2; i<=n; ++i) { 68 a = read(),b = read();//表示a连向了i,权值为b。 69 add_edge(a,i,b); 70 } 71 dfs1(1); 72 dfs2(1); 73 for (int i=1; i<=n; ++i) { 74 printf("%d\n",max(dp[i][0],dp[i][2])); 75 } 76 } 77 return 0; 78 }
后来发现了一种比较简单的方法,不需要dp,
根据性质:树上任意某个节点到树上任意节点的最远距离的端点一定会是树上直径的两个端点之一
那么求出树的直径,然后在处理一下就好了,题解代码网上都有
标签:numbers can center 一个 cti most tmp nbsp acm
原文地址:http://www.cnblogs.com/mjtcn/p/7799234.html