给定一棵树,点有颜色(黑/白),将树分成若干部分,使得每一部分有且仅有一个黑点。
设
f[i][1]表示以i为根的子树,最上面的连通块内有一个黑点的方案总数
f[i][0]表示以i为根的子树,最上面的连通块内没有黑点的方案总数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 100010;
ll f[maxn][2];
int first[maxn];
struct edg
{
int next;
int to;
}e[maxn<<1];
int a[maxn];
int e_sum;
int n;
inline void add_edg(int x,int y)
{
e_sum++;
e[e_sum].next=first[x];
first[x]=e_sum;
e[e_sum].to=y;
}
ll Power(ll x,ll y)
{
x%=mod;ll ans=1;
while(y)
{
if(y&1) ans=(ans*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return ans;
}
ll calc(ll x)
{
return Power(x,mod-2);
}
void dp(int x,int fa)
{
f[x][a[x]]=1;f[x][0]=1;
ll mul=1;
for(int i=first[x];i;i=e[i].next)
{
int w=e[i].to;
if(w==fa) continue;
dp(w,x);
if(a[x]) f[x][1]=(f[x][1]*f[w][0])%mod,f[x][0]=(f[x][0]*f[w][0])%mod;
else f[x][0]=(f[x][0]*f[w][0])%mod;
mul=(mul*f[w][0])%mod;
}
if(a[x]==0)
{
ll tmp=0;
for(int i=first[x];i;i=e[i].next)
{
int w=e[i].to;
if(w==fa) continue;
f[x][1]=(f[x][1]+mul*calc(f[w][0])%mod*f[w][1])%mod;
tmp=(tmp+mul*calc(f[w][0])%mod*f[w][1])%mod;
}
f[x][0]+=tmp;
}
}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n-1;i++)
{
int x;
scanf("%d",&x);
add_edg(i+1,x+1);add_edg(x+1,i+1);
}
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
dp(1,-1);
cout<<f[1][1];
return 0;
}
/*
3
0 0
0 1 1
*/