解题报告:
这题感觉是树形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;
}