目录:
分析:
首先是用树形dp,这个小编就不废话了,小编将着重点放在动态方程上:
我们用
表示在i点开饭店,
则相反,而我们就可以进行分类讨论了:
1)
.即在i点开饭店时,我们的子节点都不能开饭店
2)
.即当不在i点开饭店时,我们的子节点可以开可以不开,那我们就选择最优解
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
int f[100001][2],ls[100001],x[100001],c=0;
struct edg{
int to,next;
}e[200001];
void add(int a,int b)
{
e[++c]=(edg){b,ls[a]};
ls[a]=c;
}
void dp(int a,int b)
{
f[a][1]=x[a];
f[a][0]=0;
for(int i=ls[a];~i;i=e[i].next)
{
int to=e[i].to;
if(to==b) continue;
dp(to,a);
f[a][1]+=f[to][0];
f[a][0]+=max(f[to][1],f[to][0]);
}
return;
}
int main()
{
memset(ls,-1,sizeof ls);
int n=read();
for(int i=1;i<=n;i++) x[i]=read();
int a,b;
for(int i=1;i<n;i++)
{
a=read();b=read();
add(a,b);add(b,a);//建邻接表
}
dp(1,0);
printf("%d",max(f[1][0],f[1][1]));
return 0;
}