前言: 考试树形结构太频繁惹菜鸡钧钧屁也不会!(雾
1.树的直径:
众所周知的两种求法:
- 两遍\(dfs\):
信奥不需要证明
第一遍\(dfs\)搜到树的最深叶节点,然后把这个叶节点拎起来作为根再\(dfs\)到最深叶节点。
*最深
指按照边长算距离根节点最远。
代码:
void dfs_R1(int x, int fa, int depth) {
if(depth > Max) Max = depth, Rs = x;
for(int i = head[x]; i; i = edg[i].nxt) {
if(edg[i].v == fa) continue;
dfs_R1(edg[i].v, x, depth + edg[i].w);
}
}
void dfs_R2(int x, int fa, int depth) {
if(depth > ans) ans = depth, Re = x;
for(int i = head[x]; i; i = edg[i].nxt) {
if(edg[i].v == fa) continue;
dfs_R2(edg[i].v, x, depth + edg[i].w);
}
}
- 树形\(DP\) :
对于每个节点,维护其子树中的最长链和次长链,设数组f[x][1]
表示最长链,f[x][2]
表示次长链。更新时,若“连接儿子的边\(+\)此儿子子树中的最长链”大于当前最长链,则当前最长链变为次长链,最长链变为连接儿子的边\(+\)此儿子子树中的最长链,若大于次长链小于最长链则只更新次长链。树的直径必然为某一节点子树中的最长链\(+\)次长链。
代码:
void dp_R(int x, int fa) {
for(int i = head[x]; i; i = edg[i].nxt) {
if(edg[i].v == fa) continue;
dp_R(edg[i].v, x);
if(edg[i].w + f[edg[i].v][1] > f[x][1])
f[x][2] = f[x][1], f[x][1] = edg[i].w + f[edg[i].v][1];
else if(edg[i].w + f[edg[i].v][1] > f[x][2])
f[x][2] = f[edg[i].v][1] + edg[i].w;
ans = max(f[x][1] + f[x][2], ans);
}
}