287. 积蓄程度

题目链接:https://www.acwing.com/problem/content/289/

思路: 换根法, 首先因为叶子节点要定义为正无穷,所以选一个不是叶子节点的根

开始dfs即可,然后考虑父节点更新子节点,对于非叶子节点v 首先cnt[v]就是下半部分的答案

考虑上半部分的答案 可以通过 u的dp[u] 来得到, 只需要减去u流向v的贡献,再和这条边取个min

即是 v向上流到u的贡献

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=2e5+10;
 4 const int mod=998244353;
 5 #define ll long long
 6 #define ull unsigned long long
 7 #define pi pair<int,ll>
 8 #define fi first
 9 #define sc second
10 #define pb push_back
11 vector<pi>E[maxn];
12 ll cnt[maxn];
13 ll dp[maxn];
14 
15 void dfs(int u,int fa)
16 {
17     cnt[u]=0;
18     if(E[u].size()==1) cnt[u]=1e10;
19     for(auto &v:E[u])
20     {
21         if(v.fi==fa) continue;
22         dfs(v.fi,u);
23         cnt[u]+=min(cnt[v.fi],v.sc);
24     }
25 }
26 
27 void dfs22(int u,int fa)
28 {
29     for(auto &v:E[u])
30     {
31         if(v.fi==fa) continue;
32         if(E[v.fi].size()==1)
33         {
34             dp[v.fi]=min(v.sc,dp[u]-v.sc);
35         }
36         else
37         {
38             dp[v.fi]=cnt[v.fi]+min(dp[u]-min(cnt[v.fi],v.sc),v.sc);
39             dfs22(v.fi,u);
40         }
41     }
42 }
43 
44 
45 int main()
46 {
47     ios::sync_with_stdio(0);
48     cin.tie(0);
49     int t;
50     cin>>t;
51     while(t--)
52     {
53         int n;
54         cin>>n;
55         for(int i=1;i<=n;i++) E[i].clear();
56         for(int i=1;i<n;i++)
57         {
58             int u,v,w;
59             cin>>u>>v>>w;
60             E[u].pb({v,w});
61             E[v].pb({u,w});
62         }
63         int rt=1;
64         while(rt<=n&&E[rt].size()==1) rt++;
65         if(rt==n+1)
66         {
67             cout<<E[1][0].sc<<'\n';
68             continue;
69         }
70         dfs(rt,0);
71         dp[rt]=cnt[rt];
72         dfs22(rt,0);
73         ll ans=0;
74         for(int i=1;i<=n;i++) ans=max(ans,dp[i]);
75         cout<<ans<<'\n';
76     }
77 
78 }
View Code

 

 

换根法有两种考虑方式 一是考虑 当前要更新的v 分为上下部分来更新

二是考虑 v和u 的答案有什么不同来更新

posted @ 2021-03-05 20:29  canwinfor  阅读(91)  评论(0)    收藏  举报