解题报告:
这题感觉是树形dp,但想不出来怎么做,看了题解,题解的意思是先从根开始dfs用子树的信息更新根,f数组先定义出包括i的子树中最大的白点减去黑点,由于黑点是0我们可以把它变成-1,那么就是等价于求子树的最大和,然后递归完,除了根以外,每个点都成为过儿子节点,那么我们要考虑根节点对他的影响啦,假设 j 是 子节点 u 是根结点,如果f j 小于0 那么他不在u的最优解里,所以f j 的转移是 max(f[j],f[j]+f[u]); 如果f j 大于等于0 那么他在u的最优解里 , 那么我们要么就只考虑子树最优解 要么就考虑它父节点的最优解
ac代码:

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=200010;
const int mod=10007;
int n,m;
int a[N];
int idx,h[N],ne[N*2],e[N*2];
int f[N];
void add(int a,int b)
{
   
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa)
{
   
	f[u]=a[u];
	for(int i=h[u];~i;i=ne[i])
	{
   
		int j=e[i];
		if(j==fa)	continue;
		dfs(j,u);
		f[u] = max(f[u],f[u]+f[j]);
	}
}
void dfs2(int u,int fa)
{
   
	for(int i=h[u];~i;i=ne[i])
	{
   
		int j=e[i];
		if(j==fa)	continue;
		if(f[j]>0)	f[j]=max(f[j],f[u]);
		else	f[j] = max(f[j],f[j]+f[u]);
		dfs2(j,u);
	}
}
int main()
{
   
	cin >> n;
	for(int i=1;i<=n;i++)
	{
   
		cin>>a[i];
		if(a[i]==0)
			a[i]=-1;
	}
	memset(h,-1,sizeof h);
	for(int i=0;i<n-1;i++)
	{
   
		int a,b;
		cin>>a>>b;
		add(a,b);
		add(b,a);
	}
	dfs(1,-1);
	dfs2(1,-1);
	for(int i=1;i<=n;i++)
		cout<<f[i]<<' ';
	cout<<endl;
	return 0;
}