CF 461B Appleman and Tree 树形DP
Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other vertices are colored white.
Consider a set consisting of k (0 ≤ k < n) edges of Appleman's tree. If Appleman deletes these edges from the tree, then it will split into (k + 1) parts. Note, that each part will be a tree with colored vertices.
Now Appleman wonders, what is the number of sets splitting the tree in such a way that each resulting part will have exactly one black vertex? Find this number modulo 1000000007 (109 + 7).
The first line contains an integer n (2 ≤ n ≤ 105) — the number of tree vertices.
The second line contains the description of the tree: n - 1 integers p0, p1, ..., pn - 2 (0 ≤ pi ≤ i). Where pi means that there is an edge connecting vertex (i + 1) of the tree and vertex pi. Consider tree vertices are numbered from 0 to n - 1.
The third line contains the description of the colors of the vertices: n integers x0, x1, ..., xn - 1 (xi is either 0 or 1). If xi is equal to 1, vertex i is colored black. Otherwise, vertex i is colored white.
Output a single integer — the number of ways to split the tree modulo 1000000007 (109 + 7).
3
0 0
0 1 1
2
6
0 1 1 0 4
1 1 0 0 1 0
1
10
0 1 2 1 4 4 4 0 8
0 0 0 1 0 1 1 0 0 1
27
题意:
一棵树,n个节点,编号为0~n-1
每一个节点涂有黑色或者白色,1代表黑色,0代表白色
若在树上去掉k条边,就把树分成k+1部分,每一个部分也是一棵树,若每一部分都有且只有一个节点是黑色,
则这是一个合理的操作。
求合理操作的方案数%(1e9+7)
如果把黑色看成节点的值为1,白色看成节点的值为0
一棵树的值=树上所有节点的值之和
则这道题转化为:
把一棵树分成若干个部分,每一部分的值都为1的方案数。
树形DP
dp[i][0] : 以i为根的子树,i所在部分的值为0的方案数%mod
dp[i][1] : 以i为根的子树,i所在部分的值为1的方案数%mod
以root=0进行DFS
则输出:dp[0][1]
代码:
1 #include<cstdio> 2 #include<cstring> 3 4 using namespace std; 5 6 const int maxn=1e5+5; 7 const int mod=1e9+7; 8 #define ll long long 9 10 struct Edge 11 { 12 int to,next; 13 }; 14 Edge edge[maxn<<1]; 15 int head[maxn]; 16 int tot=0; 17 ll dp[maxn][2]; 18 int cost[maxn]; 19 20 void init() 21 { 22 memset(head,-1,sizeof head); 23 memset(dp,0,sizeof dp); 24 } 25 26 void addedge(int u,int v) 27 { 28 edge[tot].to=v; 29 edge[tot].next=head[u]; 30 head[u]=tot++; 31 } 32 33 void solve(int ); 34 void dfs(int ,int ); 35 36 int main() 37 { 38 init(); 39 int n; 40 scanf("%d",&n); 41 for(int i=1;i<n;i++) 42 { 43 int p; 44 scanf("%d",&p); 45 addedge(i,p); 46 addedge(p,i); 47 } 48 for(int i=0;i<n;i++) 49 { 50 scanf("%d",&cost[i]); 51 } 52 solve(n); 53 return 0; 54 } 55 56 void solve(int n) 57 { 58 dfs(0,-1); 59 printf("%d\n",(int)dp[0][1]); 60 return ; 61 } 62 63 void dfs(int u,int pre) 64 { 65 if(cost[u]) 66 { 67 dp[u][1]=1; 68 dp[u][0]=0; 69 } 70 else 71 { 72 dp[u][0]=1; 73 dp[u][1]=0; 74 } 75 for(int i=head[u];~i;i=edge[i].next) 76 { 77 int v=edge[i].to; 78 if(v==pre) 79 continue; 80 dfs(v,u); 81 if(cost[u]) 82 { 83 dp[u][1]*=(dp[v][0]+dp[v][1]); 84 dp[u][1]%=mod; 85 } 86 else 87 { 88 dp[u][1]=dp[u][1]*(dp[v][0]+dp[v][1])+dp[u][0]*dp[v][1]; 89 dp[u][1]%=mod; 90 dp[u][0]*=(dp[v][0]+dp[v][1]); 91 dp[u][0]%=mod; 92 } 93 } 94 }