CF1381D The Majestic Brown Tree Snake 题解
设 $s\to t$ 的长度为 $L$,记 $p$ 为关键点,当且仅当从 $p$ 能引出 $3$ 条互不相交的,长度为 $L$ 的路径,
则只需判断蛇的某一端能否到达关键点。
以某个关键点为根,依次将蛇的两端移动至其子树内最深的叶子,
若某一时刻蛇的两端有祖先关系,则蛇可以到达关键点。
树上倍增维护蛇的移动即可。最多移动 $O(n)$ 次,所以复杂度 $O(n\log n)$。
#include <cstdio>
#include <algorithm>
using namespace std;
struct E
{
int v, t;
} e[200050];
int T, n, s, t, l, c, R, d[100050], r[100050], z[100050][3], a[100050], f[100050][23], h[100050];
void A(int u, int v)
{
e[++c] = {v, h[u]};
h[u] = c;
}
void X(int u, int k)
{
z[a[u] = u][0] = z[u][1] = z[u][2] = 0;
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != k)
{
X(v, u);
if (z[v][0] + 1 > z[u][0])
z[u][2] = z[u][1], z[u][1] = z[u][0], z[u][0] = z[v][0] + 1, a[u] = a[r[u] = v];
else if (z[v][0] + 1 > z[u][1])
z[u][2] = z[u][1], z[u][1] = z[v][0] + 1;
else if (z[v][0] + 1 > z[u][2])
z[u][2] = z[v][0] + 1;
}
}
void Y(int u, int k)
{
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != k)
{
int x = z[u][v == r[u]] + 1;
if (x > z[v][0])
z[v][2] = z[v][1], z[v][1] = z[v][0], z[v][0] = x;
else if (x > z[v][1])
z[v][2] = z[v][1], z[v][1] = x;
else if (x > z[v][2])
z[v][2] = x;
Y(v, u);
}
}
void D(int u, int k)
{
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != k)
{
d[v] = d[f[v][0] = u] + 1;
for (int j = 1; j <= 20; ++j)
f[v][j] = f[f[v][j - 1]][j - 1];
D(v, u);
}
}
int K(int u, int k)
{
for (int i = 0; i <= 20; ++i)
if (k >> i & 1)
u = f[u][i];
return u;
}
bool P(int x, int y)
{
if (d[x] > d[y])
swap(x, y);
return K(y, d[y] - d[x]) == x;
}
int main()
{
scanf("%d", &T);
while (T--)
{
scanf("%d%d%d", &n, &s, &t);
for (int i = 1, u, v; i < n; ++i)
scanf("%d%d", &u, &v), A(u, v), A(v, u);
d[s] = 1;
D(s, 0);
l = d[t];
X(1, 0);
Y(1, 0);
R = 0;
for (int i = 1; i <= n; ++i)
if (z[i][0] >= l - 1 && z[i][1] >= l - 1 && z[i][2] >= l - 1)
{
R = i;
break;
}
if (R)
{
d[R] = 1;
for (int i = 0; i <= 20; ++i)
f[R][i] = R;
X(R, 0);
D(R, 0);
while (!P(s, t))
{
int u = s, v = t, x = d[a[s]] - d[s];
s = a[s];
t = K(t, x);
x = d[a[t]] - d[t];
t = a[t];
s = K(s, x);
if (u == s && v == t)
break;
}
puts(P(s, t) ? "YES" : "NO");
}
else
puts("NO");
c = 0;
for (int i = 1; i <= n; ++i)
d[i] = r[i] = z[i][0] = z[i][1] = z[i][2] = a[i] = h[i] = 0;
}
return 0;
}