这题不难......我是用倍增 LCA 实现的,很简单。不会看这里:https://www.cnblogs.com/BlueInRed/p/12644150.html
注意输出的顺序......是深度 宽度 距离
......
注意这里距离的定义......
以上是我这题做了一个晚上之后得出的惨痛教训。
来看看最大深度怎么求。
倍增 LCA 不是在预处理 (f) 数组的时候就能顺便求出每个点的深度了吗?
然后每一次比较一下深度更新答案即可。
这里一定要注意:最大深度不一定是第 (n) 个点。
预处理+求深度 (d) 数组代码
void dfs(int u, int fa)
{
d[u] = d[fa] + 1;
deep = max(deep, d[u]);
for(int i=1; (1<<i) <= d[u]; i++)
f[u][i] = f[ f[u][i-1] ][i-1];
for(int i=head[u]; i; i=nxt[i])
{
int y=ver[i];
if(y == fa) continue;
f[y][0] = u;
dfs(y, u);
}
}
来看宽度怎么求。
这个比较麻烦。
如果直接统计,我们无法得知一个点到底在哪一层,从而无从得知每一层的宽度。
那么注意到同一层不同点的深度是一样的,所以直接把深度当成层的编号,用深度更新每一层的宽度即可。
更新之后比较一下即可。
代码:
for(int i=1; i<=n; i++) wid[ d[i] ] += 1; //这个结点所在的深度的宽度+1
int width=0;
for(int i=1; i<=n; i++) width = max(width, wid[ d[i] ]); //找出宽度最大的那一层
来看距离怎么求。
首先求出 ( ext{LCA}(u,v))。
题目中说:
注:结点间距离的定义:由结点向根方向(上行方向)时的边数×2,与由根向叶结点方向(下行方向)时的边数之和。
上行方向的边数就是(假设 ( ext{LCA}(u,v)=lca) ):
[d_u-d_{lca}
]
实际上就是前缀和的思想:减去要求的区间之外的部分。
×2就是:
[(d_u-d_{lca}) imes 2
]
下行方向的边数更好求了,就是:
[(d_v-d_{lca})
]
综上,(u,v) 的距离就是:
[(d_u-d_{lca}) imes 2+(d_v-d_{lca})
]
故我们可以得出最终代码:
#include <cstdio>
#include <algorithm>
using namespace std;
int tot, n, ver[100010], nxt[100010], head[100010];
int f[100010][30], u, v, d[100010], wid[100010], deep;
void add(int x, int y)
{
ver[++tot] = y; nxt[tot] = head[x]; head[x] = tot;
}
void dfs(int u, int fa)
{
d[u] = d[fa] + 1;
deep = max(deep, d[u]);
for(int i=1; (1<<i) <= d[u]; i++)
f[u][i] = f[ f[u][i-1] ][i-1];
for(int i=head[u]; i; i=nxt[i])
{
int y=ver[i];
if(y == fa) continue;
f[y][0] = u;
dfs(y, u);
}
}
int LCA(int a, int b)
{
if(d[a] < d[b]) swap(a, b);
for(int i=20; i>=0; i--)
{
if(d[ f[a][i] ] >= d[b]) a = f[a][i];
if(a == b) return a;
}
for(int i=20; i>=0; i--)
if(f[a][i] != f[b][i])
a = f[a][i], b = f[b][i];
return f[a][0]; // return f[b][0];
}
int main(void)
{
scanf("%d", &n);
for(int i=1; i<=(n-1); i++)
{
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
dfs(1, 0);
scanf("%d%d", &u, &v);
// printf("%d
", (d[u]+d[v] - 2 * LCA(u, v)) * 2 );
int lca = LCA(u, v);
for(int i=1; i<=n; i++) wid[ d[i] ] += 1;
int width=0;
for(int i=1; i<=n; i++) width = max(width, wid[ d[i] ]);
printf("%d
%d
%d
", deep, width, (d[u] - d[lca])*2 + d[v]-d[lca] );
return 0;
}