思路
题意:给一个树,求分割该树使得,分割后每一个连通块中有且只有一个黑点 状态定义:dp[i][0/1],dp[i][0]表示以i为根节点的树其中 i 所在的连通块没有黑点的方案数,dp[i][1]表示以 i 为根节点的树其中 i 所在连通块有黑点的方案数 状态转移:
dp[i][1]=dp[i][1]*(dp[j][0]+dp[j][1])+dp[i][0]*dp[j][1] 因为如果 i 所在连通块有黑点,总共有三种情况,
①:i 所在连通块本来就存在黑点,所以对于以 j 为根节点的子树 来说,j 这个点在有黑点的连通块里面,这样就把连接 j 和 i 的边去掉即可。 ②:i 所在连通块本来就存在黑点,所以对于以 j 为根节点的子树 来说,j 这个点不在有黑点的连通块里面,这样就连接 j 和 i 。 ③:i 所在连通块本来不存在黑点,所以对于以 j 为根节点的子树 来说,j 这个点必须在有黑点的连通块里面,这样就连接 j 和 i 。 在根据乘法原理计算即可 dp[i][0]=dp[i][0]*(dp[j][1]+dp[j][0]) 总共两种情况
①:i 所在连通块本来不存在黑点,所以对于以 j 为根节点的子树 来说,j 这个点在有黑点的连通块里面,这样就把连接 j 和 i 的边去掉即可。 ②:i 所在连通块本来不存在黑点,所以对于以 j 为根节点的子树 来说,j 这个点不在有黑点的连通块里面,这样就连接 j 和 i 。 同理在根据乘法原理计算即可
代码
#include <cstdio>
#include <cstring>
#define ll long long
#define N 100005
const int mod= 1e9 + 7 ;
int head[ N] , e, n;
ll dp[ N] [ 2 ] ;
struct E
{
int to, next;
} edge[ N] ;
inline void addedge ( int u, int v)
{
edge[ e] . to= v;
edge[ e] . next= head[ u] ;
head[ u] = e++ ;
}
void dfs ( int u)
{
int i;
for ( i= head[ u] ; i; i= edge[ i] . next)
{
int v= edge[ i] . to;
dfs ( v) ;
dp[ u] [ 1 ] = ( dp[ u] [ 1 ] * ( dp[ v] [ 1 ] + dp[ v] [ 0 ] ) % mod+ dp[ u] [ 0 ] * dp[ v] [ 1 ] % mod) % mod;
dp[ u] [ 0 ] = dp[ u] [ 0 ] * ( dp[ v] [ 1 ] + dp[ v] [ 0 ] ) % mod;
}
}
int main ( )
{
scanf ( "%d" , & n) ;
int i, tmp;
e= 1 ;
for ( i= 1 ; i< n; i++ ) scanf ( "%d" , & tmp) , addedge ( tmp, i) ;
for ( i= 0 ; i< n; i++ ) scanf ( "%d" , & tmp) , dp[ i] [ tmp] = 1 ;
dfs ( 0 ) ;
printf ( "%I64d\n" , dp[ 0 ] [ 1 ] ) ;
return 0 ;
}