cf461 B. Appleman and Tree

题意:

有 n 个节点的树,节点为黑色或白色。现在可以从中删去若干条边,使得剩下的每个连通块恰有一个黑色节点。问有多少种删边方案。

思路:

树形dp,\(f(u,0/1)\) 表示 \(u\) 所在的连通块中无黑点/恰有一个黑点。答案为 \(f(1,1)\)

dfs 到节点 u,当前的 f[fa] 表示 fa 和 fa 的所有位于 u 左边的儿子子树组成的集合,记此集合为 \(S\)。现在要把 u子树也加入 fa 的集合,集合变为 \(S\cup u\)

\(f[S\cup u][1] = f[S][0] * f[u][1]_{(连接fa与u )} + f[S][1] * (f[u][0]_{(连接)}+f[u][1]_{(断开)})\)

\(f[S\cup u][0] = f[S][0] * (f[u][0]_{(连接)}+f[u][1]_{(断开)})\)

注意要用旧的集合 \(S\) 来更新,所以上面两个转移顺序不能换

ll f[N][2];
void dfs(int u, int fa) {
    for(int v : G[u]) if(v != fa)
        dfs(v, u);
    
    if(~fa) f[fa][1] = (f[fa][0] * f[u][1] + f[fa][1] * (f[u][0] + f[u][1])) % mod,
        f[fa][0] = f[fa][0] * (f[u][0] + f[u][1]) % mod;
}

void sol() {
    cin >> n; for(int i = 0, p; i < n - 1; i++)
        cin >> p, G[i+1].pb(p), G[p].pb(i+1);
    for(int i = 0, col; i < n; i++) cin >> col, f[i][col] = true;
    
    dfs(0, -1);
    cout << f[0][1];
}

posted @ 2022-03-30 20:58  Bellala  阅读(94)  评论(0)    收藏  举报