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 }
换根法有两种考虑方式 一是考虑 当前要更新的v 分为上下部分来更新
二是考虑 v和u 的答案有什么不同来更新

浙公网安备 33010602011771号