题解:首先肯定不能暴力了,那就是中间有规律,网络赛的时候找了种规律,天真,最后重新看出规律,对于每条边,如果能找找出此条边在全排列中一共走了多少次就好了,那么一共走了多少次了,对于每条边,数出左边有多少个点,右边有多少个点,然后左右两两组合,最后还有个捆绑排列,也就是两两组合的组合在n的全排列中共出现了多少了,此时将这两个组合捆绑住,也就是(n-1)!了,最后使用dfs得出答案,dfs有个窍,我刚开始还用边跑的dfs,天真。
附上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e5+10;
ll f[maxn];
ll jiecheng()
{
f[1]=1;
for(int i=2;i<=maxn;i++){
f[i]=(f[i-1]*i)%mod;
}
}
int n;
struct edge{
ll u,v,w;
int next;
};
edge edges[maxn*2];
int tot,head[maxn];
int used[maxn];
ll ans;
void add_edges(ll u,ll v,ll w)
{
edges[tot].u=u;
edges[tot].v=v;
edges[tot].w=w;
edges[tot].next=head[u];
head[u]=tot++;
}
ll dfs(int u,int pre)
{
int sz1=1;
for(int i=head[u];~i;i=edges[i].next){
if(edges[i].v==pre){
continue;
}
int sz2=dfs(edges[i].v,u);
sz1+=sz2;
ans=(ans+(ll)sz2*(ll)(n-sz2)%mod*f[n-1]%mod*2%mod*(ll)edges[i].w%mod)%mod;
}
return sz1;
}
void solve()
{
dfs(1,-1);
printf("%lld\n",ans);
}
int main()
{
ll u,v,w;
jiecheng();
while(scanf("%d",&n)!=EOF){
memset(head,-1,sizeof(head));
tot=0;
for(int i=0;i<n-1;i++){
scanf("%lld%lld%lld",&u,&v,&w);
add_edges(u,v,w);
add_edges(v,u,w);
}
ans=0;
solve();
}
return 0;
}