题目传送门
1 /*
2 题意:寻找一个根节点,求min f(u) = ∑ρ(v, u) * p(v)。ρ(v, u)是u到v的距离,p(v)是v点的权值
3 树形DP:先从1出发遍历第一次,sum[u]计算u到所有子节点v的路径权值(之后的点路径有叠加,所以先把路径权值加后*w),
4 计算f[u](缺少u节点以上的信息)。然后再遍历一遍,之前是DFS从下往上逆推,现在是顺推,把u节点以上的信息加上
5 dp的部分不是很多,两个DFS函数想了很久,还是没完全理解:(
6 */
7 #include <cstdio>
8 #include <cstring>
9 #include <algorithm>
10 #include <vector>
11 using namespace std;
12
13 typedef long long ll;
14 const int MAXN = 1e5 + 10;
15 const int INF = 0x3f3f3f3f;
16 int p[MAXN];
17 ll f[MAXN];
18 ll sum[MAXN];
19 vector<pair<int, int> > G[MAXN];
20
21 void DFS1(int u, int rt)
22 {
23 f[u] = 0; sum[u] = p[u];
24 for (int i=0; i<G[u].size (); ++i)
25 {
26 int v = G[u][i].first; int w = G[u][i].second;
27 if (v == rt) continue;
28 DFS1 (v, u);
29 f[u] += f[v] + sum[v] * w; sum[u] += sum[v];
30 }
31 }
32
33 void DFS2(int u, int rt)
34 {
35 for (int i=0; i<G[u].size (); ++i)
36 {
37 int v = G[u][i].first; int w = G[u][i].second;
38 if (v == rtGym 100496H House of Representatives) continue;
39 f[v] = f[u] - sum[v] * w + (sum[u] - sum[v]) * w;
40 sum[v] = sum[u];
41 DFS2 (v, u);
42 }
43 }
44
45 int main(void) //Gym 100496H House of Representatives
46 {
47 // freopen ("H.in", "r", stdin);
48 freopen ("house.in", "r", stdin);
49 freopen ("house.out", "w", stdout);
50
51 int n;
52 while (scanf ("%d", &n) == 1)
53 {
54 for (int i=1; i<=n; ++i) scanf ("%d", &p[i]);
55 for (int i=1; i<=n; ++i) G[i].clear ();
56
57 for (int i=1; i<=n-1; ++i)
58 {
59 int u, v, w; scanf ("%d%d%d", &u, &v, &w);
60 G[u].push_back (make_pair (v, w));
61 G[v].push_back (make_pair (u, w));
62 }
63
64 DFS1 (1, -1); DFS2 (1, -1);
65
66 int p = 1;
67 for (int i=2; i<=n; ++i)
68 {
69 if (f[i] < f[p]) p = i;
70 }
71
72 printf ("%d %I64d
", p, f[p]);
73 }
74
75 return 0;
76 }