题意:给一棵树的边赋边权,要求边权积等于m(m以质因数分解形式给出),且边上1的个数尽量少,目的最大化两两点对路径和之和
吕老板讲过,树上统计两两点对路径和,考虑每条边的贡献,对于一条边,它贡献的次数就是它两侧子树的大小之积,用dfs求出siz,贡献次数w就是siz*(n-siz)
把w数组从大到小排序,如何安排m?
m的质因数分解形式也从大到小排序,要求1最少,那就优先给每个w排上一个数,由排序不等式(或者直觉),大的配大的
首先,考虑边数比m分解的数多的情况,那就尽量安排大的在前面,后面的补1
再考虑边数比m分解数少的情况,想到两个情况,把从大到小安排后,把剩下的安排到最大;或者从小到大安排,再安排剩下的到最大
考虑贡献次数(w_1)和(w_2)的两条边,安排(a,b,c)三个数(顺序默认从大到小),结果就是(acw_1+bw_2)或(abw_1+cw_2),显然第二个大,所以策略是最大的安排到最大的边,直到剩下的正好覆盖剩余的边
呼之欲出
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
int ret=0,f=1;char c;
while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
while(isdigit(c))ret=ret*10+c-'0',c=getchar();
return ret*f;
}
#define pc putchar
#define space() pc(' ')
#define nextline() pc('
')
void pot(int x){if(!x)return;pot(x/10);pc('0'+x%10);}
void out(int x){if(!x)pc('0');if(x<0)pc('-'),x=-x;pot(x);}
const int MOD = 1e9+7;
const int MAXN = 100005;
struct Edge{
int next,to;
}e[MAXN<<1];
int head[MAXN],ecnt;
inline void add(int x,int y){
e[++ecnt].next = head[x];
e[ecnt].to = y;
head[x] = ecnt;
}
typedef long long ll;
int n,m;
ll ps[MAXN],w[MAXN];
int siz[MAXN];
void dfs(int x,int pre){
siz[x]=1;
for(int i=head[x];i;i=e[i].next){
int v=e[i].to;
if(v==pre) continue;
dfs(v,x);
siz[x]+=siz[v];
}
}
void solve(){
memset(siz,0,sizeof(siz));
memset(head,0,sizeof(head));
memset(ps,0,sizeof(ps));
ecnt=0;
//clear
n=rd();
int x,y;
for(int i=1;i<=n-1;i++){
x=rd();y=rd();
add(x,y);add(y,x);
}
m=rd();
for(int i=1;i<=m;i++){
ps[i]=rd();
}
sort(ps+1,ps+1+m);
reverse(ps+1,ps+1+m);
dfs(1,-1);
for(int i=1;i<=ecnt;i+=2){
int u=e[i].to;
int v=e[i+1].to;
ll mn=min(siz[u],siz[v]);
w[(i+1)>>1]=1ll*mn*(n-mn);
// w[(i+1)>>1]=mn;
}
sort(w+1,w+1+(n-1));
reverse(w+1,w+1+(n-1));
// cerr<<"DEBUG:";
// for(int i=1;i<=n-1;i++) cerr<<w[i]<<" ";
// cerr<<endl;
ll ans=0;
if((n-1)>=m){
for(int i=1;i<=n-1;i++){
int y=ps[i];
if(y==0) y=1;
ans+=(ll)(1ll*w[i]*y);
ans%=MOD;
}
// cerr<<"ANS:";
cout<<ans<<endl;
return;
}else{
ll tmp=1;
for(int i=1;i<=(m-n+2);i++){
tmp*=(ll)(1ll*ps[i]);
tmp%=MOD;
}
ans+=(ll)(1ll*tmp*w[1]);
ans%=MOD;
for(int i=2;i<=n-1;i++){
int j=i+m-n+1;
ans+=(ll)(1ll*w[i]*ps[j]);
ans%=MOD;
}
// cerr<<"ANS:";
cout<<ans<<endl;
return;
}
}
int main(){
int t=rd();
while(t--) solve();
return 0;
}