题目链接:https://hihocoder.com/problemset/problem/1199

  题意:一棵以1为根的树,每个点有一个p值和q值,到这个点需要当前分数大于等于p,然后消耗掉(p-q)的分数。问一种遍历方式,使得一开始在1所需的分数最小并能够遍历完所有的点。

  分析见代码:

 

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 #include <vector>
 5 using namespace std;
 6 const int N = 100000 + 100;
 7 
 8 // https://hihocoder.com/contest/hiho109/problem/1
 9 int n;
10 int a[N],b[N];
11 vector<int> G[N];
12 
13 bool cmp(int x,int y) {return b[x] > b[y];}
14 
15 int dfs(int u,int fa)
16 {
17     vector<int> child;
18     for(int i=0;i<G[u].size();i++)
19     {
20         int v = G[u][i];
21         if(v == fa) continue;
22         dfs(v, u);
23         child.push_back(v);
24     }
25     // 先找能返还最多分数的点,这个贪心策略还是挺有道理的
26     sort(child.begin(), child.end(), cmp);
27     int &m = a[u];
28     int cost = a[u] - b[u];
29     for(int i=0;i<child.size();i++)
30     {
31         int v = child[i];
32         // cost表示先去访问前面的点,然后再来访问v时需要花费的分数
33         if(a[v] + cost > m) m = a[v] + cost;
34         cost += a[v] - b[v];
35     }
36     // b在这里可以表示返还的钱,自然可以等于u点最少需要的分数,减去花费cost.
37     b[u] = m - cost;
38 }
39 
40 int main()
41 {
42     while(scanf("%d",&n) == 1 && n)
43     {
44         for(int i=1;i<=n;i++) {scanf("%d%d",a+i,b+i);G[i].clear();}
45         for(int i=1;i<n;i++)
46         {
47             int u,v;scanf("%d%d",&u,&v);
48             G[u].push_back(v);
49             G[v].push_back(u);
50         }
51         dfs(1,-1);
52         printf("%d\n",a[1]);
53     }
54     return 0;
55 }