[ABC259F] Select Edges 题解

Solution

考虑树形 dp

我们可以注意到节点 i 的相邻的边中被选中的不超过 di 条,显然我们可以定义状态 dpu,k 表示节点 u 连接子节点的边有 k 条的最大值。

但是此处没有给定 di 的范围,所以对于一个节点最多可能会有 n1 个点,所以时间复杂度和空间的复杂度都是无法接受的。

既然考虑一个点与子节点之间边的情况不行,那么是否可以反过来想,考虑当前点是否与父节点相连的情况,此时每一个点只有与父节点的边选与不选两种情况。

现在我们重新定义状态,设 dpu,0/1 为当前点为 u,是否与父节点连边的最大值。

但是在求解的过程中我们需要保证每个节点 i 相连的边不超过 di 条。

我们可以发现不选与子节点的边一定是一种情况,我们首先可以定义一个变量 sum 为当前点 u 与其任意一个子节点 v 的边都不选。

此时如果我们选择其中一个节点与其的连边,那么这时答案的增量记为 Δv=dpv,1+w(u,v)dpv,0

此时我们选出的就是最大的几个正数,由于不超过 n 个,考虑直接排序。

对于 dpu,1 选出只需最大的 du1 个,应为它需要连接父节点。

特殊的,如果 du=0,那么 dpu,1 不存在,应赋值为极小值。

若我们假定这棵树的根节点为 1,那么答案为 max{dp1,0,dp1,1}

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define int long long
#define inl inline
using namespace std;
const int N = 3e5, INF = 1e9;
int n;
int d[N + 5];
int dp[N + 5][2];
struct Edge {
	int v, w;
	Edge () {}
	Edge (int vv, int ww) : v(vv), w(ww) {}
};
vector<Edge> G[N + 5];
inl bool cmp(int x, int y) { return x > y; }
inl void dfs(int u, int fa) {
	int sum = 0;
	vector<int> stk;
	for (auto it : G[u]) {
		int v = it.v, w = it.w;
		if (v == fa)
			continue;
		dfs(v, u), sum += dp[v][0];
		stk.push_back(dp[v][1] - dp[v][0] + w);
	}
	sort(stk.begin(), stk.end(), cmp);
	for (int i = 0; i < min((int)stk.size(), d[u] - 1); i++)
		sum += max(0ll, stk[i]);
	dp[u][0] = sum + ((d[u] && stk.size() > d[u] - 1) ? max(0ll, stk[d[u] - 1]) : 0);
	dp[u][1] = !d[u] ? -INF : sum;
}
signed main() {
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> d[i];
	for (int i = 1, u, v, w; i < n; i++) {
		cin >> u >> v >> w;
		G[u].push_back(Edge(v, w)), G[v].push_back(Edge(u, w));
	}
	dfs(1, 0);
	cout << max(dp[1][0], dp[1][1]);
	return 0;
}
posted @   zhou_ziyi  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示