【51Nod1500】苹果曼和树

来源:互联网 发布:淘宝美工助理工作内容 编辑:程序博客网 时间:2024/06/15 18:16

苹果曼有一棵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;}
原创粉丝点击