这是一道很考细节的题。硬是怼着题解改了一小时的细节 。
这题的主要思路就是把路径拆分成线段,走过一次相当于加一次线段。所以我们可以把走过和没走过的分成两块,而即将要走那条路作为我们状态转移的关键。故,当前边权值即为((走过的子树里黑色点没走的部分的黑色点)+(走过的子树里白色点没走的部分的白色点))* 当前边权,所以我们每次枚举父节点u子树里的黑色点个数,以及当前遍历到的子节点v子树里的黑点数,而当前边权就是u与v想链接的边。
//
// Created by acer on 2021/2/16.
//
//判断子串,不同子串个数,所有子串字典序第i大,最长公共子串
#include <cstring>
#include <iostream>
#include "string"
#define int long long
#define mem(x, i) memset(x,i,sizeof(x))
using namespace std;
const int MAXN = 3e4 + 10;
int head[MAXN];
int cnt =0 ;
struct node{
int to,next;
int w;
}a[MAXN];
int n,k;
int zia[MAXN];
int dp[3000][3000];
void add(int u,int v,int w)
{
a[++cnt].to = v;
a[cnt].w = w;
a[cnt].next = head[u];
head[u] = cnt;
}
int dfs(int u,int fa){
zia[u] = 1;dp[u][0] = dp[u][1] =0;
for (int i = head[u]; i ; i = a[i].next) {
int v = a[i].to;
if (v == fa) continue;
dfs(v,u);
zia[u]+=zia[v];
for (int j = min(zia[u],k); j >= 0; --j) {
if (dp[u][j] != -1) dp[u][j] += dp[v][0] + zia[v] *(n - zia[v] - k)*a[i].w;
for (int l = min(zia[v],j); l > 0; --l) {
if (dp[u][j-l] == -1) continue;
int val = (l*(k-l)+(zia[v]-l)*(n - k + l - zia[v]))*a[i].w;
dp[u][j] = max(dp[u][j],dp[u][j-l]+dp[v][l]+val);
}
}
}
}
signed main()
{
cin >> n >> k;
for (int i = 2; i <= n; ++i) {
int u,v,w;
cin >> u >> v >> w;
add(u,v,w);
add(v,u,w);
}
mem(dp,-1);
dfs(1,0);
cout << dp[1][k] << endl;
}