苹果曼有一棵n个点的树。有一些(至少一个)结点被标记为黑色,有一些结点被标记为白色。
现在考虑一个包含k(0 ≤ k < n)条树边的集合。如果苹果曼删除这些边,那么会将这个树分成(k+1)个部分。每个部分还是一棵树。
现在苹果曼想知道有多少种边的集合,可以使得删除之后每一个部分恰好包含一个黑色结点。答案对1000000007 取余即可。
Input
单组测试数据。
第一行有一个整数n (2 ≤ n ≤ 10^5),表示树中结点的数目。
第二行有n-1个整数p[0],p[1],…,p[n-2] (0 ≤ p[i] ≤ i)。表示p[i]和(i+1)之间有一条边。结点从0开始编号。
第三行给出每个结点的颜色,包含n个整数x[0],x[1],…,x[n-1] (x[i]是0或者1)。如果x[i]是1,那么第i个点就是黑色的,否则是白色的。
Output
输出答案占一行。
Input示例
3
0 0
0 1 1
Output示例
2
题解
f[u]表示u子树有一个黑点的方案数
g[u]表示u子树没有黑点的方案数
f[u]=f[u]*g[son]+f[u]*f[son]+g[u]*f[son]
g[u]=g[u]*g[son]+g[u]*f[son]
代码
#include<bits/stdc++.h>
#define mod 1000000007
#define inf 10000000
#define N 100015
#define pa pair<long long,int>
typedef long long ll;
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
vector<int>l[100005];
int c[N],n;
ll f[N],g[N];
void dfs(int u,int pre)
{
if (c[u]) f[u]=1;
else g[u]=1;
for (int i=0;i<l[u].size();i++)
{
int v=l[u][i];
if (v==pre) continue;
dfs(v,u);
f[u]=(f[u]*g[v]+f[u]*f[v]+g[u]*f[v])%mod;
g[u]=(g[u]*g[v]+g[u]*f[v])%mod;
}
}
int main()
{
n=read();
for (int i=0;i<n-1;i++)
{
int x=read();
l[x].push_back(i+1);
l[i+1].push_back(x);
}
for (int i=0;i<n;i++) c[i]=read();
dfs(0,-1);
printf("%lld",f[0]);
return 0;
}