Maximum White Subtree(树形DP+换根,codeforces #627 div3 F题)

在这里插入图片描述

题目大意

       给一颗树,每个节点的颜色为黑色或白色,求包含节点 v v 的所有连通子图中,白色节点数与黑色节点数的最大差值。

分析过程

       设 d p [ i ] dp[i] 为包含节点 i i 所能获得的最大贡献,很显然,这个贡献就等于当把 i i 作为全树的根时,其子树的正贡献之和+其自身的贡献,我们发现好像并不能直接计算这个答案。我们可以这样做,先用 d f s dfs 预处理一下,求出每个节点的子树对其的贡献(含自身贡献),即 d p [ p a r e n t ] = a [ p a r e n t ] + max ( 0 , d p [ c h i l d r e n ] ) dp[parent]=a[parent]+\sum\max(0, dp[children]) 这个时候的 d p [ i ] dp[i] 只求出了节点下方子树的贡献;这个时候,我们再用 d f s dfs 进行最终答案的计算,从根开始(指定1为根)遍历树,每一次更新子树节点的答案,即 d p [ c h i l d r e n ] = d p [ c h i l d r e n ] + m a x ( 0 , d p [ p a r e n t ] m a x ( 0 , d p [ c h i l d r e n ] ) ) dp[children]=dp[children]+max(0,dp[parent]-max(0,dp[children])) 第二遍 d f s dfs 的实现本质上就是在轮流换根求贡献。

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 100;
int a[maxn], n, dp[maxn];
vector<int> G[maxn];
void dfs(int node, int prt){ //计算以1为整棵树的根,node为当前子树根时,其下方子树对其的贡献+该节点自身贡献 
     int i;
	 dp[node] += a[node];
	 for(i=0;i<G[node].size();++i){
	 	int to = G[node][i];
		if(prt == to) continue;
		dfs(to, node); //递归计算子树贡献 
		dp[node] += max(0, dp[to]);  
	 }
}
void dfs2(int node, int prt){ //每次以to作为整棵树的根,即叠加上方对to产生的贡献 
	int i;
	for(i=0;i<G[node].size();++i){
		int to = G[node][i];
		if(prt == to) continue;
		dp[to] += max(0, dp[node] - max(0, dp[to]));
		dfs2(to, node); 
	} 
}
int main(){
	int t, i, j, u, v;
	ios::sync_with_stdio(false);
	cin>>n;
	for(i=1;i<=n;++i){
		cin>>a[i];
		if(!a[i]) a[i] = -1;
	}
	for(i=1;i<n;++i){
		cin>>u>>v;
		G[u].push_back(v);
		G[v].push_back(u);S
	}
	dfs(1, -1);
	dfs2(1, -1);
	for(i=1;i<n;++i) cout<<dp[i]<<' ';
	cout<<dp[i];
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42968686/article/details/105329852