From bbb6826a45f5f0ec0504ab4417caf8c747f0dc56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Wed, 17 Jan 2024 14:40:35 +0800 Subject: [PATCH] 'commit' --- TangDou/Topic/HuanGenDp/SubTree.cpp | 83 +++++++++++---------------- TangDou/Topic/【换根DP】专题.md | 52 ++++++++++++++++- 2 files changed, 85 insertions(+), 50 deletions(-) diff --git a/TangDou/Topic/HuanGenDp/SubTree.cpp b/TangDou/Topic/HuanGenDp/SubTree.cpp index 613765f..7cf6652 100644 --- a/TangDou/Topic/HuanGenDp/SubTree.cpp +++ b/TangDou/Topic/HuanGenDp/SubTree.cpp @@ -2,68 +2,53 @@ using namespace std; #define int long long #define endl "\n" +const int N = 100010; -const int N = 100010, M = N << 1; -// 链式前向星 -int e[M], h[N], idx, w[M], ne[M]; -void add(int a, int b, int c = 0) { - e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; -} - -int f[N], g[N]; -int n, mod; -int pro1[N], pro2[N]; - -void dfs1(int u, int fa) { - f[u] = 1; - vector edgeson; +int n, m; - for (int i = h[u]; ~i; i = ne[i]) { - int v = e[i]; - if (v == fa) continue; - dfs1(v, u); +vector s[N]; +int dp[N], pd[N]; - f[u] = f[u] * (f[v] + 1) % mod; - edgeson.push_back(v); // 将子节点加入集合,方便之后操作 +void dfs1(int x, int fa) { + for (int i : s[x]) { + if (i != fa) { + dfs1(i, x); + dp[x] = dp[x] * (dp[i] + 1) % m; + } } - int pre1 = 1; - int pre2 = 1; - - for (int i = 0; i < edgeson.size(); i++) { - pro1[edgeson[i]] = pre1; - pre1 = pre1 * (f[edgeson[i]] + 1) % mod; - } // 预处理前缀积 - - for (int i = edgeson.size() - 1; i >= 0; i--) { - pro2[edgeson[i]] = pre2; - pre2 = pre2 * (f[edgeson[i]] + 1) % mod; - } // 预处理后缀积 } -void dfs2(int u, int fa) { - if (fa == 0) - g[u] = 1; // 特判根节点 - else - g[u] = (g[fa] * (pro1[u] * pro2[u] % mod) % mod + 1) % mod; - - for (int i = h[u]; ~i; i = ne[i]) { - int v = e[i]; - if (v == fa) continue; - dfs2(v, u); - } +void dfs2(int x, int fa) { + int t = pd[x]; + for (int i : s[x]) + if (i != fa) + pd[i] = pd[i] * t % m; + t = 1; + for (int i : s[x]) + if (i != fa) + pd[i] = pd[i] * t % m, t = t * (dp[i] + 1) % m; + t = 1; + reverse(s[x].begin(), s[x].end()); + for (int i : s[x]) + if (i != fa) + pd[i] = pd[i] * t % m, t = t * (dp[i] + 1) % m; + for (int i : s[x]) + if (i != fa) { + ++pd[i]; + dfs2(i, x); + } } -signed main() { - // 初始化链式前向星 - memset(h, -1, sizeof h); - cin >> n >> mod; +signed main() { + cin >> n >> m; + for (int i = 1; i <= n; i++) dp[i] = pd[i] = 1; for (int i = 1; i < n; i++) { int a, b; cin >> a >> b; - add(a, b), add(b, a); + s[a].push_back(b), s[b].push_back(a); } dfs1(1, 0); dfs2(1, 0); - for (int i = 1; i <= n; i++) cout << f[i] * g[i] % mod << endl; + for (int i = 1; i <= n; ++i) cout << dp[i] * pd[i] % m << endl; } \ No newline at end of file diff --git a/TangDou/Topic/【换根DP】专题.md b/TangDou/Topic/【换根DP】专题.md index c91f8f7..4aec604 100644 --- a/TangDou/Topic/【换根DP】专题.md +++ b/TangDou/Topic/【换根DP】专题.md @@ -1269,7 +1269,57 @@ signed main() { } ``` #### [$V-Subtree$](https://www.luogu.com.cn/problem/AT_dp_v) -https://blog.csdn.net/Emm_Titan/article/details/123875298 +**题意** +给定一棵 $N$ 个节点的树,现在需要将每一个节点染成黑色或白色。 + +对于每一个节点 $i$,求强制把第 $i$ 节点染成黑色的情况下,所有的黑色节点组成一个联通块的染色方案数,答案对 $M$ 取模。 + +**分析** +树上求方案数,而且要求每一个顶点对应的方案数,还是在 $AT$ 的 $DP$ 列表里的,考虑进行换根$DP$。 + + +**求解** +第一步,先求出以第 $i$ 个点为根的子树中,根节点是黑色的黑连通块数量,就是一个普通的树上 $DP$,状态从子节点转移,结果储存在 +$dp[i]$ 里。 + +```cpp {.line-numbers} +void DP(int x,int fa){ + for(int i:s[x]){ + if(i!=fa){ + DP(i,x); + dp[x]=dp[x]*(dp[i]+1)%m;//子树全白也是一种情况 + } + } +} +``` +第二步,求出第 $i$ 个节点通过它的父亲节点,与此节点的兄弟节点们及其子孙节点和此节点的祖先节点们,所能构成的黑连通块的总数,结果存在 $pd[i]$ 里。 +这里有换根的思想。首先它的父亲肯定是黑的,这时把它的父亲节点视作根节点,把它自己及其子树删去,和第一步同样的方法求解。 + +```cpp {.line-numbers} +void PD(int x,int fa){ + Int t=pd[x]; + for(int i:s[x])//它的祖先们转移过来的 + if(i!=fa) + pd[i]=pd[i]*t%m; + t=1; + for(int i:s[x])//它左侧的兄弟们转移过来的 + if(i!=fa) + pd[i]=pd[i]*t%m,t=t*(dp[i]+1)%m; + t=1; + std::reverse(s[x].begin(),s[x].end()); + for(int i:s[x])//它右侧的兄弟们转移过来的 + if(i!=fa) + pd[i]=pd[i]*t%m,t=t*(dp[i]+1)%m; + for(int i:s[x])if(i!=fa){ + ++pd[i]; + PD(i,x); + } +} +``` +显而易见的,步骤一和步骤二中的答案互不相干,可以让节点上方随意排布,节点下方随意排布。根据乘法原理,答案即为 +$dp[i] \times pd[i]$ 。 + + #### [$AcWing$ $1148$ 秘密的牛奶运输](https://www.cnblogs.com/littlehb/p/16054005.html)