题解: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 中国大陆许可协议进行许可。

posted @   一只小咕咕  阅读(44)  评论(1编辑  收藏  举报
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.
点击右上角即可分享
微信分享提示