codeforeces 543D

The country has n cities and n - 1 bidirectional roads, it is possible to get from every city to any other one if you move only along the roads. The cities are numbered with integers from 1 to n inclusive.
All the roads are initially bad, but the government wants to improve the state of some roads. We will assume that the citizens are happy about road improvement if the path from the capital located in city x to any other city contains at most one bad road.
Your task is — for every possible x determine the number of ways of improving the quality of some roads in order to meet the citizens’ condition. As those values can be rather large, you need to print each value modulo 1 000 000 007 (109 + 7).

设f[x]表示以x为根的子树恰好符合要求的方案数。
f[x]=(f[son[1]]+1)*(f[son[2]]+1)…同时题目还要求换根,所以我们记g[x]表示从x向上延伸的方案数(就是整棵树除了x的子树以外的部分),由父亲来更新儿子。假设x为第i个儿子,则g[x]=(f[son[1]]+1)(f[son[2]]+1)…(f[son[i-1]]+1)(f[son[i+1]]+1)…g[fa]
最终的答案是ans[i]=g[i]*f[i].
Tips:叶子节点的f值是1,根节点的g值是1.

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn=200000+10;
const int md=1000000007;
long long f[maxn],h[maxn],pre[maxn],suf[maxn];
int n;
vector<int> g[maxn];
void dfs1(int p)
{
  f[p]=1;
  for(int i=0;i<g[p].size();i++)
  {
    int v=g[p][i];dfs1(v);
    f[p]=(f[p]*(f[v]+1))%md;
  }
}
void dfs2(int p)
{
  if(!g[p].size()) return;
  pre[0]=1;
  for(int i=1;i<=g[p].size()-1;i++)
  {
    int v=g[p][i-1];
    pre[i]=(pre[i-1]*(f[v]+1))%md;
  }
  suf[g[p].size()-1]=1;
  for(int i=g[p].size()-2;i>=0;i--)
  {
    int v=g[p][i+1];
    suf[i]=(suf[i+1]*(f[v]+1))%md;
  }
  for(int i=0;i<g[p].size();i++)
  {
    int v=g[p][i];
    h[v]=(h[p]*suf[i]%md*pre[i]%md)%md;
    h[v]=(h[v]+1)%md;
  }
  for(int i=0;i<g[p].size();i++) dfs2(g[p][i]);
}
int main()
{

  scanf("%d",&n);
  for(int i=2;i<=n;i++)
  {
    int x;scanf("%d",&x);
    g[x].push_back(i);
  }
  dfs1(1);h[1]=1;dfs2(1);
  for(int i=1;i<=n;i++)
  {
    long long ans=h[i]*f[i]%md;
    printf("%I64d ",ans);  
  }
  return 0;
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值