xiaoshu_ci

[GESP2406 八级] 最远点对

题目传送门

本题可以知道,是求树的直径,但是得特判是否多出了黑色节点。

这道题我们可以使用树形dp。
因为我们有两种状态,分别是最后以黑色结尾和白色结尾。
dp就表示最多能走多远。

dp转移方程:
我们知道,对于id来说,我们可以最多走相邻的节点最多走的个数加一,并取max。
id有两种状态,分别是最后以黑色结尾和最后与白色结尾的情况。
然后,我们的ans为这些东西取max。
最后,我们输出即可。

//dp[id][i] 表示id在什么颜色结尾的情况下最久走多远
dp[id][i] = max(dp[id][i], dp[x][i] + 1);

dfs定义方式

void dfs(int id, int fa, int cnt/*表示有多少黑色节点*/, int cnt2/*表示一共经过了多少节点*/) {
	if(cnt > k) { //特判:是否超过限制
		return;
	}
	
	for(int x : v[id]) {
		if(x == fa) { //判断是否走过该节点
			continue;
		}
		
		dfs(x, id);
		
		//转移方程
		ans = max(ans, max(dp[id][2] + dp[x][1], dp[id][1] + dp[x][2]) + 1);
		dp[id][1] = max(dp[id][1], dp[x][1] + 1);
		dp[id][2] = max(dp[id][2], dp[x][2] + 1);
	}
}

最后,易错点!!!

这里的话,记得一定是分清楚哪个代表黑,哪个代表白。

代码:

/**
 * @file: [GESP2406 八级] 最远点对.cpp
 * @author: xiaoshu
 * @date: 2026-05-14 17:34:38
 * 小暑的防伪
 **/
#include "bits/stdc++.h"
#pragma GCC diagnostic ignored "-Wunused-variable"
#define Main signed main
#define int long long
#define ios_ return 0;						\
ios_base::sync_with_stdio(0);				\
ios::sync_with_stdio(0);					\
const char endl = '\n';						\
cin.tie(nullptr);							\
cout.tie(nullptr);

using namespace std;

int n;
int idx = 0;
int ans = 0;

int c[200010] = { };
int dp[200010][10] = { };

vector <int> v[200010];

void dfs(int id, int fa) {
	dp[id][1] = INT_MIN;
	dp[id][2] = INT_MIN;
	dp[id][c[id] + 1] = 0;
	
	for(int x : v[id]) {
		if(x == fa) {
			continue;
		}
		
		dfs(x, id);
		
		ans = max(ans, max(dp[id][2] + dp[x][1], dp[id][1] + dp[x][2]) + 1);
		dp[id][1] = max(dp[id][1], dp[x][1] + 1);
		dp[id][2] = max(dp[id][2], dp[x][2] + 1);
	}
}

Main() {
	ios_;
	
	cin >> n;
	for(int i = 1; i <= n; i++) {
		cin >> c[i];
	}
	
	for(int i = 1; i < n; i++) {
		int x, y;
		cin >> x >> y;
		v[x].push_back(y);
		v[y].push_back(x);
	}
	
	dfs(1, 0);
	
	cout << ans << endl;
	
	return 0;
}

posted on 2026-05-18 21:25  xiaoshu_ci  阅读(35)  评论(0)    收藏  举报

导航