题面
题目描述
某大学有
n
n
n 个职员,编号为
1
…
n
1\ldots n
1…n。
他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。
现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数
r
i
r_i
ri,但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。
所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
输入格式
输入的第一行是一个整数
n
n
n。
第
2
2
2 到第
(
n
+
1
)
(n + 1)
(n+1) 行,每行一个整数,第
(
i
+
1
)
(i+1)
(i+1) 行的整数表示
i
i
i 号职员的快乐指数
r
i
r_i
ri。
第
(
n
+
2
)
(n + 2)
(n+2) 到第
2
n
2n
2n 行,每行输入一对整数
l
,
k
l, k
l,k,代表
k
k
k 是
l
l
l 的直接上司。
输出格式
输出一行一个整数代表最大的快乐指数。
样例
输入
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
输出 #1复制
5
数据规模
对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 6 × 1 0 3 1\leq n \leq 6 \times 10^3 1≤n≤6×103, − 128 ≤ r i ≤ 127 -128 \leq r_i\leq 127 −128≤ri≤127, 1 ≤ l , k ≤ n 1 \leq l, k \leq n 1≤l,k≤n,且给出的关系一定是一棵树。
解析
很容易发现这是一道DP题,但以为给定的是一颗树,那么就考虑在树上DP
设
F
i
,
j
F_{i,j}
Fi,j
i
∈
{
0
,
1
}
,
j
∈
[
1
,
N
]
i\in\{0,1\},j\in[1,N]
i∈{0,1},j∈[1,N] 表示
{
要
取
第
j
号
点
字
树
内
的
快
乐
指
数
(
i
=
1
)
不
取
第
j
号
点
字
树
内
的
快
乐
指
数
(
i
=
0
)
\left\{ \begin{aligned} 要取第j号点字树内的快乐指数(i=1)\\ 不取第j号点字树内的快乐指数(i=0)\\ \end{aligned} \right.
{要取第j号点字树内的快乐指数(i=1)不取第j号点字树内的快乐指数(i=0)
转移式也就显然:(
K
K
K表示
i
i
i的儿子,
k
∈
K
k\in K
k∈K)
f
i
,
j
=
{
∑
f
k
,
0
(
j
=
1
)
∑
max
(
f
k
,
0
,
f
k
,
1
)
(
j
=
0
)
f_{i,j}=\left\{ \begin{aligned} &\sum f_{k,0} &(j=1)\\ &\sum \max(f_{k,0},f_{k,1}) &(j=0)\\ \end{aligned} \right.
fi,j=⎩⎨⎧∑fk,0∑max(fk,0,fk,1)(j=1)(j=0)
代码
#include<bits/stdc++.h>
using namespace std;
int w[10001];
vector<int>num[10001];
int f[2][10001];
int n,m;
int fr,to;
int sum;
void dfs(int u){
f[1][u]=w[u];
for(int i=0;i<num[u].size();i++){
dfs(num[u][i]);
f[1][u]+=f[0][num[u][i]];
f[0][u]+=max(f[1][num[u][i]],f[0][num[u][i]]);
}
return;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
sum^=i;
}
for(int i=1;i<=n-1;i++){
scanf("%d%d",&to,&fr);
sum^=to;
num[fr].push_back(to);
}
num[0].push_back(sum);
dfs(sum);
printf("%d\n",max(f[0][sum],f[1][sum]));
return 0;
}