“科林明伦杯”哈尔滨理工大学第十届程序设计竞赛——A.点对最大值【换根DP】

本文介绍了‘科林明伦杯’哈尔滨理工大学第十届程序设计竞赛中A题的解题思路。题目涉及换根DP算法,通过维护以每个节点为根的子树中最长链来解决问题。在遍历节点并处理子树后,更新答案和dp值。初始设置关键在于确保链的连续性,并注意避免超时和内存溢出问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目传送门


在这里插入图片描述


题解

  • 比较简单的换根DP,很容易想到。
  • 我们可以维护 d p [ i ] : dp[i]: dp[i]: 以i为根的子树中最长的链(不包括节点i的值)。
  • 对于任意结点 u u u ,我们需要子树中 最长的链mmx次大的链mx
  • 那么我们可以每次处理完节点 u u u 的子树后,更新 a n s = m m x + m x + d p [ u ] ans = mmx + mx + dp[u] ans=mmx+mx+dp[u],然后更新 d p [ u ] = m m x dp[u]=mmx dp[u]=mmx
  • 由于避免 d p [ i ] dp[i] dp[i] 所表示的链断开而错误,我们在初始化 m m x = i 结 点 的 v a l mmx=i结点的val mmx=ival,这样就可以保证,对于子树中的dp[i]表示的一定是和 i i i 结点连续的链。
  • 注意:太久没碰过题了,导致连初始化都不记得做。vector直接爆内存了。然后注意ans初始化为-INF。C++不关闭流同步可能导致超时。

AC-Code

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 7;
const int INF = 0x3f3f3f3f;

struct NODE {
	int to;
	int val;
	NODE(int t, int v) : to(t), val(v) {}
};
vector<NODE>G[maxn];
int dp[maxn];	// dp[i]:i子树价值最大链
int ans;
void add(int u, int v, int val) {
	G[u].push_back(NODE(v, val));
	G[v].push_back(NODE(u, val));
}
void dfs(int u, int fa) {
	int mmx = dp[u], mx = -INF;
	for (int i = 0; i < G[u].size(); ++i) {
		if (G[u][i].to == fa)    continue;
		int v = G[u][i].to, val = G[u][i].val;
		dfs(v, u);
		mx = max(mx, val + dp[v]);
		if (mx > mmx) swap(mmx, mx);
	}
	ans = max(ans, mx + mmx);
	dp[u] = mmx;
}
int main() {
	std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int t;    cin >> t;
	while (t--) {
		int n;    cin >> n;
		for (int i = 1; i <= n; ++i)	
			G[i].clear();
		ans = -INF;
		for (int i = 2; i <= n; ++i) {
			int a, b;    cin >> a >> b;
			add(i, a, b);
		}
		for (int i = 1; i <= n; ++i)
			cin >> dp[i];
		dfs(1, -1);
		cout << ans << endl;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值