题意:一棵树,给出每两个点间有几对边。每条边都是不一样的,问有多少种方法走完这颗树。
思路:首先,对于每一个节点,假设,他的子节点没有子节点。然后计算这个的情况。令
ai
是这个点和每个子节点的边数。
sum
是边数和。则当前的情况数为
sum!∏n1ai∗∏n1(2ai)!
然后就是计算每一队父子关系的贡献
设父亲连到这个子节点有
fa
对边,子节点有
son
对子节点。对于每一对子节点往下连的边,就相当于要插入到某一对父节点与子节点的边的中间。所以模型转化为son个球,放到fa个盒子中的种数。既
Cfa−1son+fa−1
最后bfs处理一下每个点就好了
#include<bits/stdc++.h>
#define maxn 100010
#define MAXN 2000100
const long long mod=1000000007;
using namespace std;
long long fac[MAXN],inv[MAXN];
long long qpow(long long a,long long b){
long long ans=1;
a%=mod;
for(;b;b>>=1LL,a=a*a%mod)if(b&1LL)
ans=ans*a%mod;
return ans;
}
void init(void) {
fac[0]=fac[1]=1;
for(int i=2;i<MAXN;i++)fac[i]=fac[i-1]*i%mod;
inv[MAXN-1]=qpow(fac[MAXN-1],mod-2);
for(int i=MAXN-2;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
}
long long C(int n,int m) {
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
struct edge {
int to;
int v;
edge(){};
edge(int to,int v):to(to),v(v) {};
};
vector <edge> mp[maxn];
int sum[maxn];
int vis[maxn];
int main()
{
int n;
init();
scanf("%d",&n);
memset(sum,0,sizeof sum);
int x,y,c;
for(int i=1;i<n;i++) {
scanf("%d%d%d",&x,&y,&c);
mp[x].push_back(edge(y,c));
mp[y].push_back(edge(x,c));
}
memset(vis,0,sizeof vis);
queue<int>gg1;
gg1.push(1);
while(gg1.size()) {
int xx=gg1.front();
vis[xx]=1;
gg1.pop();
for(int i=0;i<mp[xx].size();i++) {
int yy=mp[xx][i].to;
if(!vis[mp[xx][i].to]) {
sum[xx]+=mp[xx][i].v;
vis[mp[xx][i].to]=1;
gg1.push(mp[xx][i].to);
}
}
}
memset(vis,0,sizeof vis);
queue<int>gg;
gg.push(1);
long long ans=1;
while(gg.size()) {
int xx=gg.front();
vis[xx]=1;
gg.pop();
ans*=fac[sum[xx]];
ans%=mod;
for(int i=0;i<mp[xx].size();i++)
if(!vis[mp[xx][i].to]){
ans*=inv[mp[xx][i].v];
ans%=mod;
ans*=fac[mp[xx][i].v*2];
ans%=mod;
int fa=mp[xx][i].v;
int son=sum[mp[xx][i].to];
ans*=C(fa+son-1,fa-1);
ans%=mod;
gg.push(mp[xx][i].to);
}
}
cout << ans << endl;
return 0;
}