联通点集如何计算,我们求dp[u]
为该子树的联通集个数有:
d
p
[
u
]
=
∏
v
(
d
p
[
v
]
+
1
)
dp[u]=\prod_v(dp[v]+1)
dp[u]=∏v(dp[v]+1)那么先求一次dfs求得每个字数的dp值,之后我们需要有一个数组存放其结点向上的一个贡献有
d
e
m
o
[
u
]
=
a
n
s
[
f
]
/
(
d
p
[
u
]
+
1
)
demo[u]=ans[f]/(dp[u]+1)
demo[u]=ans[f]/(dp[u]+1)。换根的思想。ans的答案为
a
n
s
[
u
]
=
(
d
e
m
o
[
u
]
+
1
)
∗
d
p
[
u
]
ans[u]=(demo[u]+1)*dp[u]
ans[u]=(demo[u]+1)∗dp[u]。
值得注意的是这里面有一个mod的操作,由于数据可能过大,可以用逆元求接,但当(dp[u]+1)%mod==0
,这时候逆元无法求解,需要暴力求解。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
struct edge
{
int v,nxt;
}e[maxn<<1];
int cnt;
int head[maxn];
void add_edge(int u,int v)
{
e[cnt].v=v;
e[cnt].nxt=head[u];
head[u]=cnt++;
}
long long dp[maxn];
int fa[maxn];
const int mod=1e9+7;
void dfs1(int u,int f)
{
dp[u]=1;fa[u]=f;
for(int i=head[u];~i;i=e[i].nxt){
int v=e[i].v;
if(v==f)continue;
dfs1(v,u);
dp[u]=dp[u]*(dp[v]+1)%mod;
}
}
long long demo[maxn];
long long ans[maxn];
long long ksm(long long a,long long b)
{
long long ans=1;
while(b){
if(b&1)ans=ans*a;
ans%=mod;
a=a*a;
a%=mod;
b>>=1;
}
return ans;
}
void dfs2(int u,int f)
{
if(u!=1){
if((dp[u]+1)%mod){
demo[u]=ans[f]*ksm(dp[u]+1ll,mod-2)%mod;
ans[u]=(demo[u]+1ll)*dp[u];
}else {
long long tmp=(1+demo[f]);
for(int i=head[f];~i;i=e[i].nxt){
int v=e[i].v;
if(v==fa[f]||v==u)continue;
tmp*=(dp[v]+1ll);
tmp%=mod;
}
demo[u]=tmp;
ans[u]=(tmp+1)*dp[u];
}
ans[u]%=mod;
}
for(int i=head[u];~i;i=e[i].nxt){
int v=e[i].v;
if(v==f)continue;
dfs2(v,u);
}
}
int main()
{
int n;
scanf("%d",&n);
memset(head,-1,sizeof head);
for(int i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
add_edge(a,b);
add_edge(b,a);
}
dfs1(1,0);
ans[1]=dp[1];
dfs2(1,0);
for(int i=1;i<=n;i++){
cout<<ans[i]<<endl;
}
}