CodeForces 543D:Road Improvement
题目:http://codeforces.com/problemset/problem/543/D
题意:给你一棵树,一开始边都是0,可以使任意的边变成1,对于每一个根节点求使得它到其他任一点的路径上只有一条0边的方案数。
假设只求一个根,f[u]=∏(s[v]+1)
然后移动根节点这样就可以通过遍历一遍树得到所有点的答案了。
s[v]=(s[u]/(s[v]+1)+1)*s[v] 这样当前根和根的其他子树就变成v的子树了(前面那坨就是它的贡献。。
(看起来是这样没错。。但是不能求逆元。因为s[u]可能为0 。。所以维护前缀和后缀bfs一遍就好了。。
#include<cstring> #include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<map> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 200500 #define maxk 69 #define inf 0x7fffffff #define ll long long #define mm 1000000007 using namespace std; struct data{int obj,pre; }e[maxn*2]; ll g[maxn],s[maxn],ans[maxn],pr[maxn],sc[maxn]; int head[maxn],a[maxn],vis[maxn],n,tot; int read(){ ll x=0,f=1; char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)){x=x*10+ch-'0'; ch=getchar();} return x*f; } void insert(int x,int y){ e[++tot].obj=y; e[tot].pre=head[x]; head[x]=tot; } ll ni(ll x){ ll y=mm-2,ans=1; while (y){ if (y&1) ans=ans*x%mm; x=x*x%mm; y>>=1; } return ans; } ll dfs(int u,int f){ s[u]=1; for (int j=head[u];j;j=e[j].pre){ int v=e[j].obj; if (v==f) continue; s[u]=s[u]*(dfs(v,u)+1LL)%mm; } return s[u]; } void go(){ g[1]=1; queue<int> q; clr(vis,0); q.push(1); while (!q.empty()){ int u=q.front(); q.pop(); vis[u]=1; int sum=0; for (int j=head[u];j;j=e[j].pre){ int v=e[j].obj; if (!vis[v]) a[++sum]=v; } sort(a+1,a+1+sum); pr[0]=1; rep(i,1,sum) pr[i]=pr[i-1]*(s[a[i]]+1)%mm; sc[sum+1]=g[u]; down(i,sum,1) sc[i]=sc[i+1]*(s[a[i]]+1)%mm; rep(i,1,sum) { s[a[i]]=(pr[i-1]*sc[i+1]%mm+1)%mm*s[a[i]]%mm; g[a[i]]=(pr[i-1]*sc[i+1]%mm+1)%mm; q.push(a[i]); } } } int main(){ n=read(); rep(i,2,n) { int x=read(); insert(x,i); insert(i,x); } dfs(1,0); go(); rep(i,1,n-1) printf("%lld ",s[i]%mm); printf("%lld\n",s[n]%mm); return 0; }