先说一下我用LCA的思路:输入过程中把叶子结点找出来。然后dfs找出各个点到根节点1的距离,并且记录下最长路的长度len和非根节点端点tail,而且要求出来两个端点都是叶子结点的LCA。
然后答案就是len+d[i]-d[lca(i,tail)](i为其它叶子结点)中的最大值了。
下面是T了的代码o(╯□╰)o
#pragma warning(disable:4996) #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <map> using namespace std; const int N = 100005; int first[N], nxt[N], to[N], e; int d[N];//距离1的最距离 bool vis[N]; int father[N]; int n; map<pair<int, int>, int>lca; vector<int>ans; int find_set(int x){ if (x == father[x])return father[x]; return father[x] = find_set(father[x]); } void dfs(int u, int dis){ d[u] = dis; father[u] = u; for (int i = first[u]; i != -1; i = nxt[i]){ int v = to[i]; if (father[v] == -1){ dfs(v, dis + 1); father[find_set(v)] = u; } } if (vis[u])return; for (int j = 0; j < (int)ans.size(); j++){ int i = ans[j]; if (father[i] != -1){ lca[pair<int, int>(i, u)] = lca[pair<int, int>(u, i)] = find_set(i); } } } int main(){ scanf("%d", &n); memset(vis, false, sizeof vis); memset(first, -1, sizeof first); e = 0; for (int i = 1; i < n; i++){ int u, v; scanf("%d %d", &u, &v); nxt[e] = first[u]; to[e] = v; first[u] = e++; vis[u] = true; } for (int i = 1; i <= n; i++){ if (vis[i])continue; ans.push_back(i); } memset(father, -1, sizeof father); memset(d, -1, sizeof d); dfs(1, 0); int len = 0, tail = 1; for (int i = 1; i <= n; i++){ if (len < d[i]){ tail = i; len = d[i]; } } int anss = len; for (int j = 0; j < (int)ans.size(); j++){ int i = ans[j]; if (vis[i] || i == tail)continue; int u = lca[pair<int, int>(i, tail)]; int tmp = len + d[i] - d[u]; anss = max(tmp, anss); } cout << anss << endl; return 0; }
然后说一下题解的思路吧,就是求出来dfs的时候顺便求出来每个点向下能到达的最大深度down数组。然后答案就是len+down[i]+1中的最大值了,注意下此处的 i 不能在最长路中要不会成环。。
下面是代码:
#pragma warning(disable:4996) #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int N = 100005; int first[N], nxt[N], to[N], e;//邻接表 int d[N];//距离节点1的最距离 int down[N];//向下的最大距离 int n; int fa[N];//记录父亲结点 bool vis[N];//记录该节点是否在最长路上 int tail = 0, len = 0;//记录最长路长度和端点 void dfs(int u, int dis){ down[u] = 0; d[u] = dis; if (dis > len){ len = dis; tail = u; } for (int i = first[u]; i != -1; i = nxt[i]){ int v = to[i]; if (d[v] == -1){ fa[v] = u; dfs(v, dis + 1); } down[u] = max(down[u], down[v] + 1); } } int main(){ scanf("%d", &n); memset(first, -1, sizeof first); e = 0; for (int i = 1; i < n; i++){ int u, v; scanf("%d %d", &u, &v); nxt[e] = first[u]; to[e] = v; first[u] = e++; } memset(d, -1, sizeof d); memset(fa, -1, sizeof fa); dfs(1, 0); //沿着父亲节点标记处最长路上的点 int last = tail; while (last != -1){ vis[last] = true; last = fa[last]; } int ans = len; for (int i = 1; i <= n; i++){ if (vis[i])continue; ans = max(ans, len + down[i] + 1); } cout << ans << endl; return 0; }