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];
}

浙公网安备 33010602011771号