Connecting...

P3177 [HAOI2015] 树上染色 - 洛谷

P3177 [HAOI2015] 树上染色 - 洛谷

思路

首先要想到距离和怎么算:考虑每条边贡献,即经过该边路径数乘权值。

然后就可以设计状态了,\(f_{u,k}\) 代表 \(u\) 为根子 树内有 \(k\) 个黑色的最大答案。

我们考虑转移,想不出来,于是严肃研读题解,发现十分巧妙:依次枚举 \(u\) 的子树的根 \(v\),用当前子树和之前的子树们进行答案的合并,类似淀粉质/启发式合并,可以保证最后的答案是不重不漏的。

Code

#include<bits/stdc++.h>
using namespace std;
const int N=2222;
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
int n,k;
vector<pii>g[N];
int f[N][N]/*当前u子树m个黑,对答案贡献*/,sz[N];
void dfs(int u,int fa){
	sz[u]=1;
	for(auto x:g[u]){
		int v=x.fi,w=x.se;
		if(v==fa)continue;
		dfs(v,u);
		sz[u]+=sz[v];
		for(int i=min(k,sz[u]);i>=0;--i){//枚举u子树黑点数
			for(int j=max({0ll,i-sz[u]+sz[v],sz[v]+k-n});j<=min(i,sz[v]);++j){//枚举v为rt子树黑点个数 
				int tot=j*(k-j)+(sz[v]-j)*(n-k-sz[v]+j);//多少对距离经过这边
				f[u][i]=max(f[u][i],f[u][i-j]+f[v][j]+tot*w); 
			}
		}
	}
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>k;
	for(int i=1;i<n;++i){
		int u,v,w;
		cin>>u>>v>>w;
		g[u].push_back({v,w});
		g[v].push_back({u,w});
	}
	dfs(1,0);
	cout<<f[1][k];
	return 0;
}
/*
1 0
*/
posted @ 2025-07-20 14:05  余亦宸  阅读(55)  评论(0)    收藏  举报