题意
给你n个点n-1条边的树,再给你m个素数 p i p_i pi其乘积为k,k很大。
让你给每条边赋权,且 n − 1 n-1 n−1条边权乘积为k
let ∑ i = 1 n − 1 ∑ j = i + 1 n f ( i , j ) \sum_{i=1}^{n-1}\sum_{j=i+1}^{n} f(i,j) ∑i=1n−1∑j=i+1nf(i,j)
思路
建图后跑dfs求出sz数组,然后考虑每条边被经过的次数 s z [ i ] ∗ ( n − s z [ i ] ) sz[i]*(n-sz[i]) sz[i]∗(n−sz[i])(为什么是这个公式,是因为他是一个全经过且不重边的图)
然后考虑m和n的大小,如果m过大就把p[n-1]增大,然后求和
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int maxn=2e5+10;
typedef long long ll;
#define int long long
int p[maxn],sz[maxn];
vector<int>edge[maxn];
void dfs(int u,int fa){
sz[u]=1;
for(auto v:edge[u]){
if(v==fa)continue;
dfs(v,u);
sz[u]+=sz[v];
}
}
void solve(){
int n;cin>>n;
for(int i=1;i<maxn;++i){
sz[i]=0;
edge[i].clear();
p[i]=1;
}
for(int _=1;_<n;++_){
int u,v;cin>>u>>v;
edge[u].push_back(v);
edge[v].push_back(u);
}
int m;cin>>m;
for(int i=1;i<=m;++i){
cin>>p[i];
}
if(m<n-1)m=n-1;
sort(p+1,p+1+m);
for(int i=n;i<=m;++i){
p[n-1]*=p[i];
p[n-1]%=mod;
}
dfs(1,0);
vector<int>val;
for(int i=2;i<=n;++i){
val.push_back(sz[i]*(n-sz[i]));
}
sort(val.begin(),val.end());
int ans=0;
for(int i=1;i<n;++i){
ans=(ans+(val[i-1]%mod*p[i]%mod)%mod)%mod;
}
cout<<ans<<endl;
}
signed main(){
int t;cin>>t;
while(t--){
solve();
}
}