- Quiz
- AC
- 解法
- 辺の両端のノード数の積が大きい辺に、大きい値を割り振るといい
- 木DPで根からの深さと、部分木のサイズを求めておけばいい
- 「割り振る重みが1になる辺は最小にせよ」という条件があるので、重みの個数Mが辺の本数N-1より多いかどうかで場合分けが必要。サンプルにはM<N-1の場合しかないのが不親切
- 私的メモ
void solve(){
ll N;
cin>>N;
VV G(N);
VI A(N-1);
VI B(N-1);
rep(i,N-1){
ll a,b;cin>>a>>b;
a--;b--;
G[a].push_back(b);
G[b].push_back(a);
A[i]=a;
B[i]=b;
}
VI depth(N, -1);
function<void(ll,ll,ll)> dfs_depth = [&](ll i, ll prev, ll dep){
depth[i]=dep;
for(ll to : G[i]){
if(to==prev)continue;
dfs_depth(to,i,dep+1);
}
return;
};
dfs_depth(0,-1,0);
VI dp(N, -1);
function<ll(ll,ll)> dfs = [&](ll i, ll prev){
ll sum=1;
for(ll to : G[i]){
if(to==prev)continue;
sum += dfs(to,i);
}
return dp[i]=sum;
};
dfs(0,-1);
ll M;cin>>M;
VI P(M);
rep(i,M)cin>>P[i];
RSORT(P);
VI C(N-1);
rep(i,N-1){
ll a = A[i];
ll b = B[i];
if(depth[a]>depth[b]) swap(a,b);
ll c = dp[b];
ll d = N-c;
C[i]=c*d;
}
RSORT(C);
mint ans = 0;
if(M<N-1){
P.resize(N-1,1);
rep(i,N-1){
mint w = P[i]*C[i]%mod;
ans += w;
}
}
else{
ll num = M-(N-1)+1;
mint w = C[0];
rep(i,num) w *= P[i];
ans += w;
FOR(i,1,N-1){
mint w = C[i];
w *= P[i+num-1];
ans += w;
}
}
p(ans.x);
}
int main(){
cin.tie(0);
ios::sync_with_stdio(false);
ll N;
cin>>N;
while(N--)solve();
return 0;
}
部分木サイズDP verified
- Cut 'em all!
- 039-Tree Distance(★5)
深さ verified
- 026-Independent Set on a Tree(★4)
数え上げ 木DP