题意
2000个点的带边权的树,其中m个点染黑色,其他点染白色,问你怎么染可以让任意两个同色的点的距离之和最小
思路
经典的套路
先看每一条边的贡献,对于每条边(x,y),其中fa[y]=x
那么如果y子树的染色数确定,这条边的贡献也就确定了
令f[i][j]为i这棵子树染了j个黑点的答案,那么对于i的每个儿子,显然是个背包问题
套个树形背包的板子就行了
代码
vector<pair<int,ll> >v[maxn];
#define mp make_pair
int n,m;
ll ans;
ll f[2222][2222];
int sz[maxn];
ll g(int x, int i, int num){
int y = v[x][i].fst;
ll w = v[x][i].sc;
return w*num*(m-num)+w*(sz[y]-num)*(n-sz[y]-(m-num));
}
void dfs(int x, int fa){
sz[x]=1;
for(int i = 0; i < (int)v[x].size(); i++){
int y = v[x][i].fst;
ll w = v[x][i].sc;
if(y==fa)continue;
dfs(y,x);
for(int j = min(sz[x],m); j >= 0 ; j--){
for(int k = min(sz[y],m); k >= 0; k--){
ll tmp = f[x][j]+f[y][k]+g(x,i,k);
f[x][j+k]=max(f[x][j+k],tmp);
}
}
sz[x]+=sz[y];
}
}
int main() {
scanf("%d %d", &n, &m);
for(int i = 1; i < n; i++){
int x,y;
ll w;
scanf("%d %d %lld", &x, &y, &w);
v[x].pb(mp(y,w));
v[y].pb(mp(x,w));
}
dfs(1,0);
printf("%lld",f[1][m]);
return 0;
}