题意:
给你一个有\(n\)个结点的树,每个结点有一个权值,现在你可以把任意一条边断掉,此时会形成两棵树,你需要舍去其中一棵树,并统计另外一棵树上所有结点的权值。现在你可以做若干次上述操作,问你可以获得的最大权值。
分析:
这是一个比较经典的树形\(dp\)的模型。
我们设\(dp[i]\)为以结点\(i\)为根的树的最大权值,那么对于它的儿子,我们有选和不选(不选代表把儿子的子树都割掉了)两种状态。因此我们不难发现,当前的状态可以由儿子的选和不选这两种状态转移过来(若选取该儿子,则我们只需要令权值增加\(dp[son[i]]\)即可,否则增加\(0\)),故有状态转移方程\(dp[i]+=\max(dp[son[i],0])\) 。而我们在进行\(dfs\)的过程正好是完成了自底向上更新的过程,因此我们只需要在\(dfs\)的过程中进行更新即可。
代码
#include <bits/stdc++.h>
#define maxn 16005
using namespace std;
struct Node{
int to,next;
}q[maxn<<1];
int head[maxn],cnt=0,dp[maxn],val[maxn],tmp[maxn],n;
int vis[maxn],maxx=0;
void add_edge(int from,int to){
q[cnt].to=to;
q[cnt].next=head[from];
head[from]=cnt++;
}
void init(){
memset(head,-1,sizeof(head));
cnt=0;
}
void dfs(int x){
dp[x]=val[x];
vis[x]=1;
for(int i=head[x];i!=-1;i=q[i].next){
int to=q[i].to;
if(vis[to]) continue;
dfs(to);
dp[x]+=max(dp[to],0);
}
maxx=max(maxx,dp[x]);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&val[i]);
}
init();
for(int i=1;i<n;i++){
int from,to;
scanf("%d%d",&from,&to);
add_edge(from,to);
add_edge(to,from);
}
dfs(1);
printf("%d\n",maxx);
return 0;
}