很是套路性的一个东西,记录一下,防止遗忘
设\(f[i]\)表示以\(i\)为根,到其子树的叶节点的最大距离。node
考虑如何用子节点更新父节点,
当前点到叶节点的最大距离=max{子节点到叶节点的距离+当前点到子节点的距离}。ios
设\(u\)为当前节点,\(v\)为\(u\)的子节点,\(dis(u,v)\)是从\(u->v\)这条路径上的距离
获得转移方程:
\[f[u]=max\{f[v]+dis(u,v)\}\]c++
如何维护以\(u\)为根的子树中的直径呢
以\(u\)为根子树的直径=max{u到叶节点的最大距离+子节点到叶节点的最大距离+\(u\)到叶节点的距离}
而后咱们钦定一个节点为根,好比1
获得转移方程:
\[ans=max\{f[u]+f[v]+dis(u,v)\}\]
\(ans\)即为树的直径
须要注意的是,咱们要在更新\(f[u]\)以前更新\(ans\),由于从u通过v到叶节点的路径是最长的路径,这样这条路径会被更新两次spa
这样作必定会选出u到叶节点最长的两条路径
分类讨论一下code
void dfs(int u, int fa) { for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v == fa) continue; dfs(v, u); ans = max(ans, f[u] + f[v] + e[i].w); f[u] = max(f[u], f[v] + e[i].w); } }
#10155. 「一本通 5.2 例 3」数字转换
边权全为1的树的直径ci
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; int n, m, num, ans; int head[N], f[N]; struct node { int nx, v; } e[N]; inline int sum(int x) { int tmp = 1; for (int i = 2; i * i <= x; ++i) if (x % i == 0) { tmp += i; if (x / i != i) tmp += x / i; } return tmp; } inline void add(int u, int v) { e[++num].nx = head[u], e[num].v = v, head[u] = num; } void dfs(int u, int fa) { for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v == fa) continue; dfs(v, u); ans = max(ans, f[u] + f[v] + 1); f[u] = max(f[u], f[v] + 1); } } int main() { ios::sync_with_stdio(false); memset(head, -1, sizeof head); cin >> n; for (int i = 1; i <= n; ++i) if (sum(i) < i) add(sum(i), i), add(i, sum(i)); dfs(1, 0); cout << ans; }