Codeforces Round #627 (Div. 3) F. Maximum White Subtree ###K ###K ###K ###K//K
题目链接:https://codeforces.ml/contest/1324/problem/F
题意:给定一棵树,每个点 为1的时白色点,为0的是黑色点,问每一个点 包含该点在内的子树的最大的 cnt白-cnt黑为多少
思路:树形dp 用上换根法, 首先以1为根跑一遍dfs 求出 所有的点的子树的最大值的, 此时只有1的值是确定的最大的,其他的点都是只有子树是最大的,上面的部分还没有计算
然后再跑一遍dfs 开始换根 每一个点,要么以子树的为最大的,要么是以除子树之外的上部为最大的,要么是子树加上上部为最大的
每次跑的时候,上面的根已经处理好了,所以跑一遍就可以得到所有的点的答案 只需讨论一下 根的dp[u] 内有无包含cnt[v]就可以了
cnt[v]>0 肯定对根由贡献,小于0肯定之前没被加入到根的贡献中 易错点在于只有ans[fa]>cnt[u]的才会去考虑上子树的贡献
当要求的是时树上所有结点的问题 并且 子节点可以由父节点的关系推来时就采用换根dp
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define pb push_back 5 const int maxn =2e5+10; 6 const int mod=1e9+7; 7 int a[maxn]; 8 int cnt[maxn]; 9 int dp[maxn]; 10 vector<int>E[maxn]; 11 12 13 14 void dfs(int u,int fa) 15 { 16 cnt[u]=a[u]; 17 for(auto &v:E[u]) 18 { 19 if(v==fa) 20 continue; 21 dfs(v,u); 22 cnt[u]+=max(0,cnt[v]); 23 24 } 25 } 26 27 void dfs2(int u,int fa) 28 { 29 for(auto &v:E[u]) 30 { 31 if(v==fa) 32 continue; 33 if(cnt[v]>=0) 34 { 35 dp[v]=cnt[v]+max(0,dp[u]-cnt[v]); 36 } 37 else 38 { 39 dp[v]=cnt[v]+max(0,dp[u]); 40 } 41 dfs2(v,u); 42 } 43 } 44 45 int main() 46 { 47 ios::sync_with_stdio(false); 48 cin.tie(0); 49 int n; 50 cin>>n; 51 for(int i=1;i<=n;i++) 52 { 53 cin>>a[i]; 54 if(!a[i]) 55 a[i]=-1; 56 } 57 for(int i=1;i<n;i++) 58 { 59 int u,v; 60 cin>>u>>v; 61 E[u].pb(v); 62 E[v].pb(u); 63 } 64 dfs(1,0); 65 dp[1]=cnt[1]; 66 dfs2(1,0); 67 for(int i=1;i<=n;i++) 68 { 69 cout<<dp[i]<<" "; 70 } 71 72 73 74 75 76 77 }

浙公网安备 33010602011771号