codeforces Round #263(div2) D. Appleman and Tree 树形dp




题意:
给出一棵树,每个节点都被标记了黑或白色,要求把这棵树的其中k条变切换,划分成k+1棵子树,每颗子树必须有1个黑色节点,求有多少种划分方法。
题解:
树形dp
dp[x][0]表示是以x为根的树形成一块不含黑色点的方案数
dp[x][1]表示是以x为根的树形成一块含一个黑色点方案数
//зїеп:1085422276
#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <queue>
#include <typeinfo>
#include <map>
#include <stack>
typedef long long ll;
#define inf 100000000
#define mod 1000000007
using namespace std;

inline ll read()
{
    ll 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;
}
//***************************************

struct ss
{

    int to,next;
}e[200005*5];
ll dp[200005][2];
int head[200005],t,vis[200005],cl[200005];
void init(){
memset(head,0,sizeof(head));
t=1;
}
void add(int u,int v)
{
    e[t].next=head[u];
    e[t].to=v;
    head[u]=t++;
}
void dfs(int x,int pre)
{
    //vis[x]=1;
    dp[x][cl[x]]=1;
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].to==pre)continue;
        dfs(e[i].to,x);
        if(cl[x]==1){
            dp[x][1]=(dp[x][1]*dp[e[i].to][0]%mod+dp[x][1]*dp[e[i].to][1])%mod;
        }
        else {

            dp[x][1]=(dp[x][1]*dp[e[i].to][0]%mod+dp[x][0]*dp[e[i].to][1]%mod+dp[x][1]*dp[e[i].to][1])%mod;
            dp[x][0]=(dp[x][0]*dp[e[i].to][1]%mod+dp[x][0]*dp[e[i].to][0])%mod;
        }


    }
}

int main()
{
    init();
    int n;
   scanf("%d",&n);
   int x;
   for(int i=0;i<n-1;i++){
    scanf("%d",&x);
    add(i+1,x);
     add(x,i+1);
   }
   for(int i=0;i<n;i++)
    scanf("%d",&cl[i]);
   dfs(0,-1);
   cout<<dp[0][1]<<endl;
    return 0;
}
代码

 

posted @ 2015-08-23 18:15  meekyan  阅读(372)  评论(0编辑  收藏  举报