链接:https://www.nowcoder.com/acm/contest/203/B
来源:牛客网
题目描述
修修去年种下了一棵树,现在它已经有n个结点了。
修修非常擅长数数,他很快就数出了包含每个点的连通点集的数量。
澜澜也想知道答案,但他不会数数,于是他把问题交给了你。
输入描述:
第一行一个整数n (1≤ n ≤ 106),接下来n-1行每行两个整数ai,bi表示一条边 (1≤ ai,bi≤ n)。
输出描述:
输出n行,每行一个非负整数。第i行表示包含第i个点的连通点集的数量对109+7取模的结果。
示例1
输入
6 1 2 1 3 2 4 4 5 4 6
输出
12 15 7 16 9 9
解题思路:对于一棵树,不妨设以1为根。那么我们可以通过一个树上dp,很容易的就能求出包含根的树上连通点集个数。方程如下。这样子就计算出了以u为根的子树中包含u的连通点集个数。
dp[u]=dp[u]*(dp[v]+1);
但是这样子只有根的答案是正确的,其他节点的答案都不正确。
假设我们已经知道了一个节点往上走的子树的答案ans,那么我们就可以很容易的计算出当前子树的正确答案
dp[u]=(ans+1)*dp[u];
那么我们怎么算出网上走的子树的答案呢?我们在深搜的时候,暴力计算其他孩子对答案的贡献即可,但是这样复杂度最坏是O(N*sqrt(N))的,所以要优化,实际上对于往上走的答案,用它父亲的答案除以dp[u]+1即可算出,但是这里要用逆元处理,会出现inv(MOD)%MOD==0的情况,这里用暴力算就好了。
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<string>
#include<vector>
#include<bitset>
using namespace std;
typedef long long ll;
const int MAXN=1000006;
const ll MOD=1e9+7;
ll pow_mod(ll a, ll k) {
ll rst = 1;
while (k) {
if (k&1) rst = rst * a % MOD;
a = a * a % MOD;
k >>= 1;
}
return rst;
}
inline ll inv(ll x) {
return pow_mod(x, MOD - 2)%MOD;
}
inline void scan_d(int &ret)
{
char c;
ret = 0;
while ((c = getchar()) < '0' || c > '9');
while (c >= '0' && c <= '9')
{
ret = ret * 10 + (c - '0'), c = getchar();
}
}
void Out(ll a)
{ // 输出外挂
if (a < 0)
{
putchar('-');
a = -a;
}
if (a >= 10)
{
Out(a / 10);
}
putchar(a % 10 + '0');
}
vector<int> G[MAXN];
ll dp[MAXN];//保存所有子树的的包含子树的根的连通点集个数
int pre[MAXN];
ll sta[MAXN];//保存不包含当前子树的包含子树的根的父亲的连通点集个数。
ll ans[MAXN];
int N;
void dfs1(int u,int fa){
pre[u]=fa;
for(int i=0;i<G[u].size();i++){
if(G[u][i]!=fa){
dfs1(G[u][i],u);
dp[u]=dp[u]*(dp[G[u][i]]+1)%MOD;
}
}
}
void dfs2(int u,int fa){
if(fa!=-1){
if((dp[u]+1)%MOD==0)//特殊情况,暴力处理
{
ll num=sta[fa]+1;
for(int i=0;i<G[fa].size();i++){
int v=G[fa][i];
if(v==pre[fa]||v==u)
continue;
num=num*(dp[v]+1)%MOD;
}
sta[u]=num;
ans[u]=(num+1)*dp[u]%MOD;
}
else//否则用逆元直接计算。
{
ll num=ans[fa]*inv(dp[u]+1)%MOD;
sta[u]=num;
ans[u]=(num+1)*dp[u]%MOD;
}
}
for(int i=0;i<G[u].size();i++){
if(G[u][i]!=fa){
dfs2(G[u][i],u);
}
}
}
int main(){
scan_d(N);
int u,v;
for(int i=1;i<N;i++){
dp[i]=1;
scan_d(u);
scan_d(v);
G[u].emplace_back(v);
G[v].emplace_back(u);
}
dp[N]=1;
dfs1(1,-1);
ans[1]=dp[1];
dfs2(1,-1);
for(int i=1;i<=N;i++){
Out(ans[i]);
puts("");
}
return 0;
}