【題意】:給出一棵樹(shù),每個(gè)節(jié)點(diǎn)都有一個(gè)權(quán)值。問(wèn)刪除一條邊之后,分開(kāi)的兩顆子樹(shù)的權(quán)值之差的最少為多少。

【題解】:dfs一次,把無(wú)向樹(shù)變成有向樹(shù)。
               順便統(tǒng)計(jì)以每個(gè)節(jié)點(diǎn)為根的子樹(shù)的權(quán)值之和,記為dp[]
               然后我們可以枚舉每一條邊,由于dfs本身就會(huì)把所有邊都走一次,所以這個(gè)枚舉的過(guò)程可以直接放在dfs里面。
               那么對(duì)于每個(gè)非葉子結(jié)點(diǎn)u,設(shè)v為u的兒子結(jié)點(diǎn)。
                        ans = min(ans, abs(sum - 2 * dp[v])), 其中 sum = ∑val[i].

               本題注意要用long long.

【代碼】:
 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "algorithm"
 5 #include "vector"
 6 #include "queue"
 7 #include "cmath"
 8 using namespace std;
 9 #define pb push_back
10 #define ll long long
11 #define maxn 100050
12 vector<int> vec[maxn];
13 const ll inf = 100000000000000LL;
14 int n, m;
15 ll val[maxn], dp[maxn], sum, ans;
16 
17 ll ABS(ll x) {
18     return (x > 0) ? x : (-x);
19 }
20 
21 void dfs(int u, int fa) {
22     int size = vec[u].size();
23     dp[u] = val[u];
24     for(int i = 0; i < size; i++) {
25         int v = vec[u][i];
26         if(v == fa) continue;
27         dfs(v, u);
28         dp[u] += dp[v];
29         ans = min(ABS(sum - 2 * dp[v]), ans);
30     }
31 }
32 
33 int main() {
34     int Case = 1, u, v;
35     while(~scanf("%d%d", &n, &m)) {
36         if(!n && !m) break;
37         for(int i = 0; i < maxn; i++) vec[i].clear();
38         ans = inf, sum = 0;
39         for(int i = 1; i <= n; i++) { 
40             scanf("%lld", &val[i]);
41             sum += val[i];
42         }
43         for(int i = 0; i < m; i++) {
44             scanf("%d%d", &u, &v);
45             vec[u].pb(v), vec[v].pb(u);
46         }
47         dfs(1, -1);
48         printf("Case %d: %lld\n", Case++, ans);
49     }
50     return 0;
51 }
52