G. Tree Destruction
思路
选择路径的中间节点的贡献是度数-2,端点是度数-1,要找最长贡献的路径。
发现一条路径一个点最多连两个边,dfs的时候保留最大和次大单链路径,dfs过程中就可以把经过这个点可能的最长贡献路径给找出来。见代码注释
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define int long long
#define pb push_back
#define pii pair<int, int>
#define FU(i, a, b) for (int i = (a); i <= (b); ++i)
#define FD(i, a, b) for (int i = (a); i >= (b); --i)
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
vector<int> adj[N];
int w[N];
int ans = -INF;
int dfs(int x, int p) {
int m1 = -1, m2 = -1; //最大 和 次大单链长度
for (int e : adj[x]) {
if (e == p)
continue;
int len = dfs(e, x);
if (len > m2) {
m2 = len;
}
if (m2 > m1)
swap(m1, m2);
}
int tans = w[x]; // 经过x点可能的最长路径(包含分叉)并更新答案
if (m2 == -1) {
tans = max(tans, tans + m1);
} else {
tans = max(tans, tans + m1 + m2);
}
ans = max(tans, ans);
return max(w[x],w[x]+m1); //返回x为端点单链的最大值
}
void solve() {
ans=-INF;
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
adj[i].clear();
w[i] = -2;
}
for (int i = 1; i <= n - 1; i++) {
int u, v;
cin >> u >> v;
adj[u].pb(v);
adj[v].pb(u);
w[u]++;
w[v]++;
}
dfs(1, -1);
cout << ans + 2 << endl;
}
signed main() {
cin.tie(0)->ios::sync_with_stdio(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
return 0;
}