洛谷 p5536 题解
题目链接:https://www.luogu.com.cn/problem/P5536
此题为树的dfs的一个应用。
思路
- 树 dfs时,可以计算每个点的深度。
如图所示
- 可以多次dfs,从而找到不同的信息。
代码片断
- 2次dfs找直径/中心
int maxLen = INT_MIN;//直径
int q;//最远点
vector<int> dist(n+1);//每个点的深度
vector<int> pathPrev(n+1);//直径找父
function<void(int, int)> dfs = [&](int u, int fa) {
for (auto v : G[u]) {
if (v == fa)continue;
dist[v] = dist[u] + 1;
pathPrev[v] = u;
if (maxLen < dist[v]) { maxLen = dist[v]; q = v; }
dfs(v, u);
}
};
dfs(1, 0);//任意点找最远点
int ret1 = q;
dist[q] = 0;
maxLen = INT_MIN;
dfs(q, 0);//最远点找另一最远点
- 找直径中心
int midPoint = q;
for (int i = 0; i < (maxLen+1)/ 2; ++i)
midPoint = pathPrev[midPoint];
- 每个点到叶子点的最远距离
vector<int> maxDeep(n + 1);//当前点能到达的最大深度
vector<int> deep(n + 1); //当前点的深度 这个与前面的dist意义相同
vector<int> eachPointToLeafLen(n+1);
function<void(int, int)> dfs3= [&](int u, int fa) {
maxDeep[u] = deep[u];
for (auto v : G[u]) {
if (v != fa) continue;
deep[v] = deep[u] + 1;//子点的深度
dfs3(v, u);
maxDeep[u] = max(maxDeep[u],maxDeep[v]);//此点最深由子深决定
}
eachPointToLeafLen[u] = (maxDeep[u] - deep[u]);//此点到最深的叶子长度
};
dfs3(midPoint, -1);
完整代码
#include <iostream>
#include <cassert>
#include <iomanip>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
#include <climits>
#include <functional>
#include <list>
#include <cstdlib>
#include <set>
#include <stack>
#include <sstream>
#include <numeric>
#include <map>
#include <algorithm>
#include <bitset>
#define endl "\n"
#define i64 long long
#define ui64 unsigned long long
#define INF 0x3f3f3f3f
#define MZ(arr) memset(arr,0,sizeof(arr))
#define MS(arr,val) memset(arr,val,sizeof(arr))
using namespace std;
namespace SLOVER {
void slove() {
int n, k,u,v;
cin >> n >> k;
vector<vector<int>> G(n + 1);
for (int i = 1; i < n; ++i) {
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
vector<int> pathPrev(n+1);
int maxLen = INT_MIN;
int q;
vector<int> dist(n+1);
auto dfs2FindDiameter = [&]() {
function<void(int, int)> dfs = [&](int u, int fa) {
for (auto v : G[u]) {
if (v != fa) {
dist[v] = dist[u] + 1;
pathPrev[v] = u;
if (maxLen < dist[v]) {
maxLen = dist[v];
q = v;
}
dfs(v, u);
}
}
};
dfs(1, 0);
int ret1 = q;
dist[q] = 0;
maxLen = INT_MIN;
dfs(q, 0);
};
dfs2FindDiameter();
int midPoint = q;
for (int i = 0; i < (maxLen+1)/ 2; ++i) {
midPoint = pathPrev[midPoint];
}
vector<int> maxDeep(n + 1);//当前点能到达的最大深度
vector<int> deep(n + 1);//当前点的深度
vector<int> eachPointToLeafLen;
function<void(int, int)> calcDeep = [&](int u, int fa) {
maxDeep[u] = deep[u];
for (auto v : G[u]) {
if (v != fa) {
deep[v] = deep[u] + 1;
calcDeep(v, u);
maxDeep[u] = max(maxDeep[u],maxDeep[v]);
}
}
eachPointToLeafLen.push_back(maxDeep[u] - deep[u]);
};
calcDeep(midPoint, -1);
sort(eachPointToLeafLen.begin(), eachPointToLeafLen.end(), std::greater<int>());
int ret = 0;
for (int i = k; i < n; ++i)ret = max(ret, eachPointToLeafLen[i] + 1);
cout << ret << endl;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
while (t--) { SLOVER::slove(); }
return 0;
}