http://codeforces.com/contest/543/problem/D
题意:
给定n个点的树
问:
一开始全是黑边,对于以i为根时,把树边白染色,使得任意点走到根的路径上不超过一条黑边,输出染色的方案数(mod 1e9+7)
思路:得知f[x]=(f[s1]+1)*(f[s2]+1)*(f[s3]+1)..*(f[sn]+1),s为x的儿子
因为要么这条边修了,里面有f[s1]方案,要吗不修,那剩下的都必须修。
由于要计算每个点的答案。
我们令up[x]为x父亲为x儿子时的f答案。可知up[x]=(fa的f前缀*fa的f后缀*up[fa])+1
最后f[x]*up[x]就是答案。
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> #include<vector> #define ll long long const ll Mod=1000000007; int tot,go[400005],first[400005],next[400005],n; ll up[400005]; ll f[400005]; std::vector<int>G[200005]; std::vector<ll>L[200005],R[200005]; int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } void dfs1(int x,int fa){ f[x]=1; for (int i=0;i<G[x].size();i++){ int pur=G[x][i]; if (pur==fa){ L[x].push_back(1); R[x].push_back(1); continue; } dfs1(pur,x); f[x]=(f[x]*(f[pur]+1))%Mod; L[x].push_back(f[pur]+1); R[x].push_back(f[pur]+1); } for (int i=1;i<L[x].size();i++) L[x][i]=(L[x][i]*L[x][i-1])%Mod; for (int i=R[x].size()-2;i>=0;i--) R[x][i]=(R[x][i]*R[x][i+1])%Mod; } void dfs2(int x,int fa,ll val){ up[x]=val; ll tmp; for (int i=0;i<G[x].size();i++){ int pur=G[x][i]; if (pur==fa) continue; tmp=val; if (i>0) tmp=(tmp*L[x][i-1])%Mod; if (i<G[x].size()-1) tmp=(tmp*R[x][i+1])%Mod; dfs2(pur,x,tmp+1); } } void solve(){ dfs1(1,0); up[1]=1; dfs2(1,0,1LL); for (int i=1;i<=n;i++) printf("%I64d ",f[i]*up[i]%Mod); } int main(){ n=read();for (int i=2;i<=n;i++){int x=read();G[x].push_back(i);G[i].push_back(x);} solve(); }