思路
应该是个比较基础的换根吧...我相信我再做几个换根
应该都能做出来的!
令表示
这个节点的联通点集的数量.
那么一个很显然的一个方程就是其中
是
的子节点.这个点的联通点集数量就是子节点的联通点集数量的选取,以及不选取的方案数的乘积.
由此我们可以的算出一个点的答案是多少.
然后考虑换根,
的子节点
的答案怎么算呢?其实挺简单的,思考
变成
的子节点,以前的
是不是会少了
这个点的答案呢?所以
当然这不够,考虑
已经成为了根节点,那么
不含
这部分的值是
拿这个值
即可.
对于为
的没有逆元,这时暴力算即可.
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
const int mod=1e9+7;
ll dp[N],ans[N];
vector<int>g[N];
ll qp(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
void dfs(int u,int fa)
{
dp[u]=1;
for(int v:g[u])
{
if(v==fa) continue;
dfs(v,u);
dp[u]=dp[u]*(dp[v]+1)%mod;
}
}
void DFS(int u,int fa)
{
if(fa==-1) ans[u]=dp[u];
else if((dp[u]+1)%mod==0)
{
dfs(u,u);
ans[u]=dp[u];
}
else ans[u]=(ans[fa]%mod*qp(dp[u]+1,mod-2)+1)%mod*(dp[u])%mod;
for(int v:g[u])
{
if(v==fa) continue;
DFS(v,u);
}
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,1);
DFS(1,-1);
for(int i=1;i<=n;i++)
printf("%lld\n",ans[i]);
return 0;
}

京公网安备 11010502036488号