背景
题意
给定一棵 \(n\) 个节点的无根树的 \(n-1\) 条边及 \(n\) 个点的权值 \(val_i\) ,求某棵子树的最大权值和。
解法
还是树形 \(dp\) 模板。
还是没有根的树。
为了方便,不妨设 \(1\) 号节点为根,则直接从 \(1\) 号点开始 \(dfs\) 出所有点的父亲即可。
不妨设 \(f_x\) 代表以 \(x\) 节点为根的子树的最大权值和。设边集为 \(E\) ,则有 \(f_x=\sum_\limits{(x,y) \in E} \max \{ f_y,0 \}+val_x\) ,要求的不是 \(f_1\) !不是 \(f_1\) !不是 \(f_1\) !要求的东西是 \(\max_\limits{i \in [1,n]} f_i\) !!!
细节
由于有负权值,记得把答案预设为 \(-inf\) 再更新。
代码
\(View\) \(Code\)
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int ret=0,f=1;
char ch=getchar();
while('9'<ch||ch<'0')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while('0'<=ch&&ch<='9')
{
ret=(ret<<1)+(ret<<3)+ch-'0';
ch=getchar();
}
return ret*f;
}
const int inf=-2147483648;
int n,val[16005],x,y,fa[16005],f[16005],ans=inf;
int num,head[32005];
bool vis[16005];
struct edge
{
int ver,nxt;
}e[32005];
inline void adde(int u,int v)
{
e[++num].ver=v;
e[num].nxt=head[u];
head[u]=num;
}
void dfs(int x)
{
vis[x]=1;
for(register int i=head[x];i;i=e[i].nxt)
{
int y=e[i].ver;
if(vis[y])
continue;
vis[y]=1;
fa[y]=x;
dfs(y);
}
}
void dp(int x)
{
f[x]=val[x];
for(register int i=head[x];i;i=e[i].nxt)
{
int y=e[i].ver;
if(y==fa[x])
continue;
dp(y);
if(f[y])
f[x]+=f[y];
}
}
int main()
{
n=read();
for(register int i=1;i<=n;i++)
val[i]=read();
for(register int i=1;i<n;i++)
{
x=read();
y=read();
adde(x,y);
adde(y,x);
}
dfs(1);
dp(1);
for(register int i=1;i<=n;i++)
ans=max(ans,f[i]);
printf("%d\n",ans);
return 0;
}