题意:在一棵树上,一开始所有的边都是坏的,如果以一个点作为首都,它到任意的其他点的每条路径上最多有一条边是坏的,则符合要求,问当1-n分别为首都的时候,修边的方式有多少种。
思路:首先dp1[i]表示以i为顶点,它下面的都是合法的情况的种类。dp1[u]=(dp1[v1]+1)*(dp1[v2]+1)*...如果u到v1的边为好的的话,那么dp[v1]就是合法即可,否则v1下面的所有边都要的好的,这种情况只有一个,所以是dp1[v1]+1。
dp2[i]表示从上往下的顶点合法情况,这个需要自己理解一下,其中用到了求逆元的方法。然后对于每一个点,就是求它的周围的点的dp+1的乘积。
AC代码如下:
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
struct node
{
int v,next;
}edge[400010];
void exgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(!b)
d=a,x=1LL,y=0LL;
else
exgcd(b,a%b,d,y,x),y-=x*(a/b);
}
ll inv(ll a,ll m)
{
ll d,x,y;
exgcd(a,m,d,x,y);
return d==1LL ? (x+m)%m : -1LL;
}
ll MOD=1e9+7,dp1[200010],dp2[200010];
int n,m,Head[200010],fa[200010],tot;
bool vis[200010];
void add(int u,int v)
{
edge[tot].v=v;
edge[tot].next=Head[u];
Head[u]=tot++;
}
void dfs1(int u)
{
int i,j,k,v;
dp1[u]=1;
for(i=Head[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(v==fa[u])
continue;
fa[v]=u;
dfs1(v);
dp1[u]=dp1[u]*(dp1[v]+1)%MOD;
}
}
ll solve(int u,int k)
{
int i,j,v;
ll ret=1;
for(i=Head[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(v==fa[u] || v==k)
continue;
ret=ret*(dp1[v]+1)%MOD;
}
return ret;
}
void dfs2(int u)
{
int i,j,k,f,v;
ll ret;
f=fa[u];
if(dp1[u]+1==MOD)
{
dp2[u]=solve(f,u)*dp2[f]%MOD;
}
else
{
dp2[u]=dp1[f]*dp2[f]%MOD*inv((dp1[u]+1)%MOD,MOD)%MOD;
}
dp2[u]=(dp2[u]+1)%MOD;
for(i=Head[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(v==fa[u])
continue;
dfs2(v);
}
}
int main()
{
int i,j,k,u,v;
ll ans;
scanf("%d",&n);
memset(Head,-1,sizeof(Head));
for(u=2;u<=n;u++)
{
scanf("%d",&v);
add(u,v);
add(v,u);
}
dfs1(1);
dp2[1]=1;
for(i=Head[1];i!=-1;i=edge[i].next)
dfs2(edge[i].v);
for(i=1;i<=n;i++)
printf("%I64d ",dp1[i]*dp2[i]%MOD);
printf("\n");
}