题解:AT_abc148_f [ABC148F] Playing Tag on Tree
思路
方便说明,我们令追的人是 A,被追的人是 B。
我们定根方便讨论。令 A 是根。
我们肯定想要 B 尽可能的往最远的点走,走到之后来回走即可。
所以我们要先处理出来 B 点能走到的点的步数,这样就可以求出距离 B 的最远点。
放个图方便理解下(图有点丑大佬轻喷)。
这时 B 点肯定会走到它父亲节点,然后往里深入。不然就会被 A 抓到,且不是最优。
所以判断 B 满足条件的点的集合中,离 A 最远的点,在同一步数的前提下,A 能走到的最远点不包括 B 点经过的点。
所以我们还要处理 A 能走到的点的步数。
最终答案就是满足上述条件的前提下,离 B 点最远的点,与 B 点的距离。
注意,最终答案要减去一。为什么?
因为 B 最终到的点肯定不是最远那个点,而是最远那个点的前面一个点。毕竟 A,B 的轮次不一样。我们可以用反证法。如果 B 最终到了最远点并且被 A 抓住,那么证明在上一步,B 和 A 也在一起,不然就不会一起走到最深一个点,那么就不合法了。
注意一下,我代码的 A 和 B 顺序是相反的了。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n, s, t, u1, v1, A, B, disA[N], disB[N], ans=0;
vector<int> a[N];
void dfs(int u, int fa)
{
for (int i=0; i<a[u].size(); i++)
{
int v=a[u][i];
if (v==fa) continue;
disA[v]=disA[u]+1;
dfs(v, u);
}
}
void dfs2(int u, int fa)
{
for (int i=0; i<a[u].size(); i++)
{
int v=a[u][i];
if (v==fa) continue;
disB[v]=disB[u]+1;
dfs2(v, u);
}
}
int main()
{
scanf("%d%d%d", &n, &A, &B);
for (int i=1; i<n; i++)
{
scanf("%d%d", &u1, &v1);
a[u1].push_back(v1);
a[v1].push_back(u1);
}
dfs(A, -1);
dfs2(B, -1);
for (int i=1; i<=n; i++)
if (disA[i]<disB[i]) ans=max(ans, disB[i]);
printf("%d", ans-1);
return 0;
}
/*
9 5 1
1 2
2 3
3 4
4 5
4 6
6 7
7 8
8 9
6
*/