题意:
给与一棵n个节点的树,求每个点的连通点集的数量?
思路:
树形结构+换根
dp[i]表示以i为根且包括i的这棵子树连通点集的数量。
ans[i]表示包括i的连通点集的数量,既结果。
父节点u与子节点v:
dp[u]= (dp[v]+1) * dp[u];(v为u的子节点)
换根时:
ans[v]=((ans[u]/(dp[v]+1))+1)*dp[v];
注意:0不能求逆元,所以当(dp[v]+1)%inf=0时,你就需要重新计算一下该点的结果。
代码:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll inf=1e9+7;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
ll dp[1000005], ans[1000005];
vector<int> g[1000005];
void dfs(int v, int f)
{
dp[v]=1;
for(int i=0;i<g[v].size();i++)
{
if(g[v][i]!=f)
{
dfs(g[v][i],v);
}
else
{
continue;
}
dp[v]=((dp[g[v][i]]+1)*dp[v])%inf;
}
}
ll fun(ll n,ll m)
{
ll s=1;
while(m)
{
if(m&1)
{
s=s*n%inf;
}
n=n*n%inf;
m=m/2;
}
return s;
}
void dfs1(int v, int f)
{
if(f!=-1)
{
if((dp[v]+1)%inf==0)
{
dfs(v,-1);
ans[v]=dp[v];
}
else
{
ans[v]=((ans[f]*fun((dp[v]+1),inf-2)%inf)+1)*dp[v]%inf;
}
}
else
{
ans[v]=dp[v];
}
for(int i=0;i<g[v].size();i++)
{
if(g[v][i]!=f)
{
dfs1(g[v][i],v);
}
}
}
int main()
{
int n;
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
int u=read(), v=read();
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,-1);
dfs1(1,-1);
for(int i=1;i<=n;i++)
{
printf("%lld\n",ans[i]);
}
return 0;
}

京公网安备 11010502036488号