CodeForces 1324F. Maximum White Subtree【换根DP】

传送门

题意

给一颗树,每个节点有 \(1\)\(-1\) 两种权值,问对于每一个点,包含它的联通块权值最大是多少。

题解

第一次写换根DP,其实并不难。相反 E 题记忆化搜索没想出来是真的煞笔。
就是一个最板的换根DP,先把 \(1\) 视作根节点,算出每个点的最大子树。
然后再进行树形DP,每次向儿子转移时将自己、父亲、其他儿子的最大总权传给儿子。

代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <queue>
using namespace std;
typedef long long LL;
const int N=2e5+10;
const int M=1e6+10;
int n,a[N],maxs[N],ans[N];
vector<int> g[N];

void dfs1(int u,int fa){
	maxs[u]=a[u];
	for(int v:g[u]){
		if(v==fa) continue;
		dfs1(v,u);
		if(maxs[v]>0) maxs[u]+=maxs[v];
	}
}

void dfs2(int u,int fa,int w){
	if(w<0) w=0;
	ans[u]=maxs[u]+w;
	for(int v:g[u]){
		if(v==fa) continue;
		if(maxs[v]>0) dfs2(v,u,w+maxs[u]-maxs[v]);
		else dfs2(v,u,w+maxs[u]);
	}
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		if(a[i]==0) a[i]=-1;
	}
	for(int i=1,u,v;i<n;i++){
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs1(1,0);
	dfs2(1,0,0);
	for(int i=1;i<=n;i++) printf("%d ",ans[i]);
	return 0;
}
posted @ 2020-03-13 09:17  BakaCirno  阅读(134)  评论(0编辑  收藏  举报