关键是状态设计
fu,i
不止表示u子树内i个黑点 子树内同色点两两之间的答案
其实应该是u子树内i个黑点 子树内同色点两两之间的答案以及子树内点和子树外点的答案
因为黑白点的个数是确定的 所以很好转移
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
#define read(x) scanf("%d",&(x))
const int N=2005;
struct edge{
int u,v,w,next;
}G[N<<1];
int head[N],inum;
#define V G[p].v
inline void add(int u,int v,int w,int p){
G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}
int n,B,W;
int size[N];
ll f[N][N];
inline void dfs(int u,int fa){
size[u]=1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa){
dfs(V,u);
for (int i=0;i<=size[V];i++)
f[V][i]+=(ll)(i*(B-i)+(size[V]-i)*(W-(size[V]-i)))*G[p].w;
for (int i=size[u];~i;i--)
for (int j=size[V];~j;j--)
f[u][i+j]=max(f[u][i+j],f[u][i]+f[V][j]);
size[u]+=size[V];
}
}
int main(){
int iu,iv,iw;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(B); W=n-B;
for (int i=1;i<n;i++)
read(iu),read(iv),read(iw),add(iu,iv,iw,++inum),add(iv,iu,iw,++inum);
dfs(1,0);
printf("%lld\n",f[1][B]);
return 0;
}