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 }
View Code

 

posted @ 2020-08-03 15:40  canwinfor  阅读(157)  评论(0)    收藏  举报