(large exttt{Read in my Blog})
做法:树形 (DP)
题目中的 (M) 到底有什么用啊QwQ
(Large exttt{Meaning})
题目“抽”字我一开始看还是有点迷惑的,其实实意就是在一棵树中取一条链,求链上的点和与它们相邻的点的个数最大。
(Large exttt{Solution})
考虑每一个点 (n) ,若这条链经过点 (n) ,那么一定是从 (n) 的一棵子树的叶子开始,到另一棵子树的叶子,显然这肯定是最大的。
这样,我们就要记录每个点两个值:与它相邻的节点个数(包括它,不包括父节点);从这个节点到它子树的某个叶子节点,这条链上有贡献的节点个数(不包括父节点),令第一个记录值为数组 (s) ,第二个记录值数组 (h) 。
(s[n]) 很好求, (h[n]) 即为 (s[n]-1+max_{vin n} h[v])(因为 (s[n]) 和 (h[v]) 都包括了 (v) 这个节点),但是注意若 (n) 事叶子节点,不用减一。
然后就可以求我们想要求的链了,记录子节点中最大和次大的的 (h) 值, 加上这个节点的相邻节点个数( (s[n]) )就好了,但要注意判重,和细节(见代码)。
(Large exttt{Code})
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <fstream>
#include <map>
#include <iostream>
#include <iterator>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <vector>
// #include <bits/stdc++.h>
using namespace std;
// #define ls now << 1
// #define rs now << 1 | 1
#define PB push_back
// #define MP make_pair
// #define int long long
// #define us unsigned
// #define LL long long
const int N = 300000;
// const int M = 1e3;
// #define re register
// const int mod = 1e;
// const int inf = 0x7fffffff;
// const double inf_double = 1e4;
// const double eps = 1e-4;
int a, siz[N + 10], ans, dp[N + 10], s[N + 10], h[N + 10];
vector<int> st[N + 10];
inline void dfs(int n, int fa)
{
s[n] = 1;
h[n] = 1;
int mx1 = 0, mx2 = 0;
for (int i = 0; i < st[n].size(); i++)
{
int v = st[n][i];
if (v == fa)
continue;
dfs(v, n);
s[n]++;
h[n] = max(h[n], h[v]);
if (h[v] >= mx1)
{
mx2 = mx1;//顺序不要错
mx1 = h[v];
}
else if (h[v] > mx2)
mx2 = h[v];
}
h[n] += s[n];
if (st[n].size())//不是叶子节点的时候
h[n]--;
int tmp = mx1 + mx2 + s[n] - (mx1 != 0) - (mx2 != 0) + (fa != 0);//注意孩子节点的个数少于2的时候,和没有父节点的时候。
ans = max(ans, tmp);//记录当前最大值
}
signed main()
{
scanf("%d%*d", &a);
int x, y;
for (int i = 1; i < a; i++)
{
scanf("%d%d", &x, &y);
st[x].PB(y);
st[y].PB(x);
}
dfs(1, 0);
printf("%d", ans);
return 0;
}