Codeforces Round #627 (Div. 3) F. Maximum White Subtree(树型dp 换根法)
https://codeforces.com/contest/1324
树型dp,换根法。题目所给定的数据结构是树,随意选择一个结点作为root根,开始dfs搜索回溯,用一个cnt数组来记录以i为根的子树对答案的贡献,这里用回溯的办法,先搜索下去再回溯上来,那么cnt[i] = cnt[i] + max(0,cnt[j]),j为i的儿子结点,只有cnt[j]是大于0 的时候,才对i结点有所贡献。这样预处理完毕之后,cnt[root]其实就是root的答案。但是其他结点不是最终答案。
dfs了一遍之后就开始换根,继续从root开始dfs,用dp数组来记录答案,dp数组包含两个部分,一个部分是以i为根的子树对dp[i]的贡献,另一部分是子树外面对答案的贡献,所以在换根的时候需要计算出子树外面的部分。假设遍历i的子树的根v,那么转移方程为 dp[v] = cnt[v] + max(0,dp[i] - max(0,cnt[v]) );
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 2e5+5; 5 int n; 6 int a[maxn],vis[maxn],cnt[maxn],dp[maxn]; 7 struct node{ 8 vector<int> v; 9 }g[maxn]; 10 void add(int u,int v){ 11 g[u].v.push_back(v); 12 g[v].v.push_back(u); 13 } 14 int dfs(int cur,int fa){ 15 vis[cur] = 1; 16 if(a[cur]) cnt[cur]++; 17 else cnt[cur]--; 18 for(auto v:g[cur].v){ 19 if(vis[v]) continue; 20 int res = dfs(v,cur); 21 if(res>0) cnt[cur] +=res; 22 } 23 return cnt[cur]; 24 } 25 void getdp(int cur,int fa){ 26 if(cur == 1) dp[cur] = cnt[cur]; 27 for(auto v : g[cur].v ){ 28 if(v == fa) continue; 29 dp[v] = cnt[v] + max(0,dp[cur] - max(0,cnt[v]) ); 30 getdp(v,cur); 31 } 32 } 33 int main() 34 { 35 scanf("%d",&n); 36 for(int i = 1;i<=n;i++){ 37 scanf("%d",&a[i]); 38 } 39 for(int i = 1;i<=n-1;i++){ 40 int u,v; 41 scanf("%d%d",&u,&v); 42 add(u,v); 43 } 44 dp[1] = dfs(1,0); 45 getdp(1,0); 46 for(int i = 1;i<=n;i++) printf("%d ",dp[i]); 47 return 0; 48 }