题解:P10894 虚树
题目传送门
树形 dp 好题。
题意
给定一棵树,每次询问删去某一子树后的树能形成的虚树数量。虽然题目叫虚树,但却是和虚树没啥关系(
思路
拿到这种题,肯定先考虑树形 dp。定义 \(f_i\) 为为 \(i\) 为根的子树好的非空点集数量,考虑转移,显然在转移时会有选 \(i\) 和不选 \(i\) 两种情况。
- 不选 \(i\),只能从若干子树中选择一棵子树中的点,方案总数为 \(\sum_{v\in son} f_v\)。
- 选 \(i\),子树就可以随便选了,直接相乘得到 \(\prod_{v\in son} (f_v+1)\)。
这样就可以进行转移了:
\[f_u=\sum_{v\in son} f_v+\prod_{v\in son} (f_v+1)
\]
现在考虑删除子树,发现本质上就是求删除掉一个点后对根产生的影响。
通过观察上式,发现 \(f_i\) 对 \(f_{fa_i}\) 的贡献是 \(f_i\times (\prod(f_{bro_i}+1)+1)\),这里 \(bro_i\) 指 \(i\) 的兄弟节点,后面这个因式可以在转移 \(f\) 时同时维护,具体的,把 \(\prod_{v\in son} (f_v+1)\) 除掉 \(f_i+1\) 即可。
然后我们处理出一个前缀积,计为 \(g\),\(g_i\) 就表示删掉 \(i\) 对根的影响,询问时再乘上 \(f_i\) 就行了,输出 \(f_1-f_i\times g_i\)。
复杂度 \(\mathcal{O(n \log n)}\),\(\log\) 是求逆元带的,注意开 long long
和一步一模防止爆炸。
代码
#include<bits/stdc++.h> #define int long long using namespace std; const int N=5e5+5; const int mod=998244353; inline int read(); int n,m,head[N],cnt; int f[N],g[N]; struct node{ int to,next; }edge[N<<1]; void add(int u,int v) { edge[++cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt; } int ksm(int a,int b) { int ans=1; while(b) { if(b&1) ans=a*ans%mod; a=a*a%mod; b>>=1; } return ans; } void dfs1(int x,int fa) { int pro=1,sum=0; for(int i=head[x];i;i=edge[i].next) { int to=edge[i].to; if(to==fa) continue; dfs1(to,x); pro=pro*(f[to]+1)%mod; sum=sum+f[to]%mod; } f[x]=pro+sum%mod; for(int i=head[x];i;i=edge[i].next) { int to=edge[i].to; g[to]=(pro*ksm(f[to]+1,mod-2)+1)%mod; } } void dfs2(int x,int fa) { for(int i=head[x];i;i=edge[i].next) { int to=edge[i].to; if(to==fa) continue; if(x!=1) g[to]=g[x]*g[to]%mod; dfs2(to,x); } } signed main() { n=read(); for(int i=1;i<n;i++) { int x,y; x=read();y=read(); add(x,y); add(y,x); } dfs1(1,0); dfs2(1,0); m=read(); while(m--) { int x; x=read(); printf("%lld\n",(f[1]-(f[x]*g[x]%mod)+mod)%mod); } return 0; } inline int read() { int x=0,f=1; char ch; ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-') f=-f;ch=getchar();} while(ch<='9'&&ch>='0') { x=(x<<1)+(x<<3)+(ch&15); ch=getchar(); } return x*f; }
本文作者:一只小咕咕
本文链接:https://www.cnblogs.com/yzxgg/p/18376361
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步