B. Appleman and Tree 树形DP

B. Appleman and Tree 树形DP

题目大意:

给你一颗大小为 n 的树,1 号节点为根节点,每棵树染色,白色或者是黑色,求有多少种分割的方式,使得分割出来的连通块中有且仅有一个黑点

题解:

感觉自己真的很久没有刷题了,不太会写这个题目,想到了状态的定义,但是不知道怎么转移。

\(dp[u][0/1]\) 表示 \(u\) 这颗子树含有 \(0/1\) 个黑色节点的连通块的方案数。

  • 如果子节点是白色,父节点是黑色,那么对 \(dp[u][1]\) 有贡献。

    \(dp[u][1] *= dp[v][0]\)

  • 如果子节点是白色,父节点也是白色,那么对 \(dp[u][0]\) 有贡献。

    \(dp[u][0]*=dp[v][0]\)

  • 如果子节点是黑色,父节点也是黑色,那么对 \(dp[u][1]\) 有贡献。断开

    \(dp[u][1] *= dp[v][1]\)

  • 如果子节点是黑色,父节点是白色,那么对 \(dp[u][1]\)\(dp[u][0]\) 都有贡献,前者不断开,后者断开

    \(dp[u][0]*=dp[v][1]\) \(dp[u][1]*=dp[v][1]\)

最后答案就是 \(dp[1][1]\)

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 2e5+10;
const int mod = 1e9+7;
typedef long long ll;
int color[maxn],head[maxn],to[maxn<<1],nxt[maxn<<1],cnt,flag[maxn];
void add(int u,int v){
    ++cnt,to[cnt] = v,nxt[cnt] = head[u],head[u] = cnt;
}
ll dp[maxn][2];
void dfs1(int u){
    if(color[u]) dp[u][1] = 1;
    else dp[u][0] = 1;
    for(int i=head[u];i;i=nxt[i]){
        int v = to[i];
        dfs1(v);
        dp[u][1] = (dp[u][1]*(dp[v][0]+dp[v][1])%mod+dp[u][0]*dp[v][1])%mod;
        dp[u][0] = dp[u][0]*(dp[v][0]+dp[v][1])%mod;
    }
//    printf("dp[%d][0]=%lld dp[%d][1]=%lld\n",u,dp[u][0],u,dp[u][1]);
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1,x;i<n;i++){
        scanf("%d",&x);
        add(x,i);
    }
    for(int i=0,x;i<n;i++){
        scanf("%d",&x);
        color[i] = x;
    }
    dfs1(0);
    printf("%lld\n",dp[0][1]);
    return 0;
}
posted @ 2021-01-31 11:59  EchoZQN  阅读(58)  评论(0编辑  收藏  举报