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;
}
posted @ 2023-11-20 21:27  5k_sync_closer  阅读(6)  评论(0编辑  收藏  举报  来源