题目链接
题目大意:
仔细读题,可以发现不是传统的子树,只是一个连通子图,给定一棵树的图,每个节点为“1”或“0”,对每个点输出包含这个点的连通子图的的1的个数-0的个数最大值。
解题思路:
第一遍dfs随便找一个点作为树根,然后dp1[u]表示包含u及其子树范围的连通子图的最大值。
第二遍dfs进行转移。
1、当前子树(包含自己)如果是正的,直接取,否则就只取当前点。
2、除了当前子树以外(必须包含父节点)如果是正的也要取,负的就不取。
解题代码:
#include<bits/stdc++.h>
using namespace std;
mt19937 rng_32(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
const int maxn=2e5+10;
struct E{
int to,nxt;
}e[maxn*2];
int head[maxn],tot=0;
void adde(int u,int v)
{
tot++;
e[tot].nxt=head[u];
e[tot].to=v;
head[u]=tot;
}
int a[maxn];
int dp1[maxn],dp2[maxn];
void dfs1(int u,int fa)
{
if (a[u]==0)
dp1[u]=-1;
else
dp1[u]=1;
for (int i=head[u];i;i=e[i].nxt)
{
int to=e[i].to;
if (to==fa)
continue;
dfs1(to,u);
if (dp1[to]>0)
dp1[u]+=dp1[to];
}
}
void dfs2(int u,int fa)
{
int tmp=(a[u]==0? -1:1);
dp2[u]=max(tmp,dp1[u])+max(0,dp2[fa]-max(0,dp1[u]));
for (int i=head[u];i;i=e[i].nxt)
{
if (e[i].to==fa)
continue;
dfs2(e[i].to,u);
}
}
int main()
{
int n;
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
int t1,t2;
for (int i=1;i<n;i++)
{
scanf("%d%d",&t1,&t2);
adde(t1,t2);
adde(t2,t1);
}
dfs1(1,1);
dfs2(1,1);
for (int i=1;i<=n;i++)
cout<<dp2[i]<<" ";
return 0;
}