Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P4281 [AHOI2008]紧急集合 / 聚会

P4281 [AHOI2008]紧急集合 / 聚会

题意,一棵树上,给定三个点,找到一个点使得三个点到该点的距离和最小,并求出该距离和。

现在假设答案为其中两个点 $x$ 和 $y$ 的 $LCA$ ,如果深度再减少,那么只有另一个点 $z$ 的距离会减少,这两个点的距离都会增大,不会再是最优解;如果向其中一个点 $x$ 再向下增加深度,那么只有 $x$ 的距离会减少,另外两个点距离都会增大——所以答案一定是三个点中两两的三个 $LCA$ 。现在有三个备选答案点,同理,越深的 $LCA$ 是越优的答案。

求 $LCA$ 有很多方法,现在习惯做树链剖分,但是当时还没学,用的是倍增。

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <iostream>
#include <cstdio>
#include <queue>
#include <climits>
#define INF INT_MAX
using namespace std;
const int N = 5e5 + 10, M = 1e6 + 10;
int n, q, st, d[N], lg[N], fa[N][21];
int idx = -1, hd[N], nxt[M], edg[M];
void bfs()
{
for (int i = 1; i <= n; i++)
d[i] = INF;
d[1] = 1;
queue <int> q;
q.push(1);
while (!q.empty())
{
int t = q.front();
q.pop();
for (int i = hd[t]; ~i; i = nxt[i])
if (d[t] + 1 < d[edg[i]])
{
d[edg[i]] = d[t] + 1;
q.push(edg[i]);
fa[edg[i]][0] = t;
for (int k = 1; 1 << k <= d[edg[i]]; k++)
fa[edg[i]][k] = fa[fa[edg[i]][k - 1]][k - 1];
}
}
}
int lca(int x, int y)
{
if (d[x] < d[y])
swap(x, y);
while (d[x] > d[y])
x = fa[x][lg[d[x] - d[y]] - 1];
if (x == y)
return x;
for (int k = lg[d[x]]; k >= 0; k--)
if (fa[x][k] != fa[y][k])
{
x = fa[x][k];
y = fa[y][k];
}
return fa[x][0];
}
void add(int x, int y)
{
nxt[++idx] = hd[x];
hd[x] = idx;
edg[idx] = y;
}
int main()
{
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++)
hd[i] = -1;
for (int i = 1; i <= n; i++)
lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
for (int i = 1, a, b; i < n; i++)
{
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
bfs();
for (int i = 1, a, b, c, t1, t2, t3, t; i <= q; i++)
{
scanf("%d%d%d", &a, &b, &c);
t1 = lca(a, b);
t2 = lca(a, c);
t3 = lca(b, c);
if (t1 == t2)
t = t3;
else if (t1 == t3)
t = t2;
else if (t2 == t3)
t = t1;
printf("%d %d\n", t, d[a] + d[b] + d[c] - d[t1] - d[t2] - d[t3]);
}
return 0;
}