[LuoguP1352][FJSC]没有上司的舞会(Link)
现在你有一棵树,每一个点有一个点权(R[i]),如果选择了(i)点,那么(i)子树上的所有的点都不能选,现在要求选择若干个点,使得点权和最大。
设(Dp[i][1])为选择(i)点的(i)子树的最大点权和,(Dp[i][0])为不选择(i)点的(i)子树的最大点权和,那么我们知道初始化为
(Dp[i][0] = sum max(Dp[Son][1], Dp[Son][0]))
(Dp[i][1] = sum Dp[Son][0])
因为如果选了(i)点,那么下面的所有的点都不能选了,但是如果没选(i),那么下面的点选不选都行。由于(i)点是由其子节点转化而来的,所以考虑从入度为零的点开始边深搜边(Dp)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
const int MAXN = 100010 ;
const int MAXM = 100010 ;
int N, H[MAXN], Tot, R[MAXN], Dp[MAXN][2], Ind[MAXN], Root ;
struct Node {
int F, T, Next ;
}E[MAXN << 1] ;
inline void Add(int F, int T) {
E[++ Tot].F = F, E[Tot].T = T ;
E[Tot].Next = H[F], H[F] = Tot ;
}
inline int Read() {
int X = 0, F = 1 ; char ch = getchar() ;
while (ch > '9' || ch < '0') F = (ch == '-' ? - 1 : 1), ch = getchar() ;
while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
return X * F ;
}
inline void Dfs(int Now) {
Dp[Now][0] = 0 ; Dp[Now][1] = R[Now] ;
for (int i = H[Now] ; i ; i = E[i].Next) {
Dfs(E[i].T) ;
Dp[Now][0] += max(Dp[E[i].T][0], Dp[E[i].T][1]) ;
Dp[Now][1] += Dp[E[i].T][0] ;
}
}
int main() {
N = Read() ;
for (int i = 1 ; i <= N ; i ++) R[i] = Read() ;
for (int j = 1 ; j <= N ; j ++) {
int X = Read(), Y = Read() ;
if (j == N) break ;
Add(Y, X) ; Ind[X] ++ ;
}
for (int i = 1 ; i <= N ; i ++)
if (! Ind[i]) {
Root = i ;
Dfs(Root) ; break ;
}
printf("%d", max(Dp[Root][0], Dp[Root][1])) ;
return 0 ;
}