P9520 [JOISC 2022 Day1] 监狱 题解

若 $u$ 路径的起点在 $v$ 路径上,则 $u$ 必须比 $v$ 先走,

若 $u$ 路径的终点在 $v$ 路径上,则 $v$ 必须比 $u$ 先走。

考虑建图,边 $u\to v$ 存在当且仅当 $u$ 必须比 $v$ 先走,

若建出的图有拓扑序,则按拓扑序操作即可,否则无解。

建图的复杂度太高,于是考虑线段树优化建图,分别考虑两个要求:

若 $u$ 路径的起点在 $v$ 路径上,则 $u$ 必须比 $v$ 先走

把每条路径向其起点连边,然后把每条路径除起点外的点向这条路径连边,

此时 $u$ 连向 $u$ 的起点,而 $u$ 路径的起点在 $v$ 路径上,所以 $u$ 的起点连向 $v$。

若 $u$ 路径的终点在 $v$ 路径上,则 $v$ 必须比 $u$ 先走

把每个终点向其路径连边,然后把每条路径向这条路径除终点外的点连边,

此时 $u$ 路径的终点在 $v$ 路径上,所以 $v$ 连向 $u$ 的终点,而 $u$ 的终点连向 $u$。

#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#define L(p) (p << 1)
#define R(p) (p << 1 | 1)
using namespace std;
struct E
{
    int v, t;
} e[10000050];
queue<int> q;
int O, n, m, c, z, a[200050], d[2000050], h[2000050];
void A(int u, int v)
{
    ++d[v];
    e[++c] = {v, h[u]};
    h[u] = c;
}
void B(int s, int t, int p)
{
    if (s == t)
    {
        a[s] = p;
        return;
    }
    A(p, L(p));
    A(p, R(p));
    A(L(p) + (n << 2), p + (n << 2));
    A(R(p) + (n << 2), p + (n << 2));
    int m = s + t >> 1;
    B(s, m, L(p));
    B(m + 1, t, R(p));
}
void C(int l, int r, int v, int o, int s, int t, int p)
{
    if (l <= s && t <= r)
    {
        if (o)
            A(v, p);
        else
            A(p + (n << 2), v);
        return;
    }
    int m = s + t >> 1;
    if (l <= m)
        C(l, r, v, o, s, m, L(p));
    if (r > m)
        C(l, r, v, o, m + 1, t, R(p));
}
struct T
{
    struct E
    {
        int v, t;
    } e[400050];
    int c, p, z[400050], d[400050], f[400050], s[400050], t[400050], b[400050], k[400050], h[400050];
    void A(int u, int v)
    {
        e[++c] = {v, h[u]};
        h[u] = c;
    }
    void X(int u)
    {
        s[u] = 1;
        for (int i = h[u], v; i; i = e[i].t)
            if (!d[v = e[i].v])
            {
                d[v] = d[f[v] = u] + 1;
                X(v);
                s[u] += s[v];
                if (s[v] > s[z[u]])
                    z[u] = v;
            }
    }
    void Y(int u, int g)
    {
        t[k[b[u] = ++p] = u] = g;
        if (z[u])
            Y(z[u], g);
        for (int i = h[u], v; i; i = e[i].t)
            if ((v = e[i].v) != f[u] && v != z[u])
                Y(v, v);
    }
    void M(int x, int y, int z, int k, int o)
    {
        while (t[x] != t[y])
        {
            if (d[t[x]] < d[t[y]])
                swap(x, y);
            C(b[t[x]], b[x] - (x == z), k, o, 1, n, 1);
            x = f[t[x]];
        }
        if (d[x] > d[y])
            swap(x, y);
        C(b[x] + (x == z), b[y] - (y == z), k, o, 1, n, 1);
    }
} T;
int main()
{
    scanf("%d", &O);
    while (O--)
    {
        scanf("%d", &n);
        B(1, n, 1);
        for (int i = 1, u, v; i < n; ++i)
            scanf("%d%d", &u, &v), T.A(u, v), T.A(v, u);
        T.X(T.d[1] = 1);
        T.Y(1, 1);
        scanf("%d", &m);
        for (int i = 1, x, y; i <= m; ++i)
        {
            scanf("%d%d", &x, &y);
            A(i + (n << 3), a[T.b[x]] + (n << 2));
            A(a[T.b[y]], i + (n << 3));
            T.M(x, y, x, i + (n << 3), 0);
            T.M(x, y, y, i + (n << 3), 1);
        }
        for (int i = 1; i <= (n << 3) + m; ++i)
            if (!d[i])
                q.push(i);
        while (!q.empty())
        {
            ++z;
            int u = q.front();
            q.pop();
            for (int i = h[u], v; i; i = e[i].t)
                if (!--d[v = e[i].v])
                    q.push(v);
        }
        puts(z == (n << 3) + m ? "Yes" : "No");
        c = z = T.c = T.p = 0;
        for (int i = 1; i <= (n << 3) + m; ++i)
            d[i] = h[i] = 0;
        for (int i = 1; i <= n; ++i)
            T.z[i] = T.d[i] = T.f[i] = T.s[i] = T.t[i] = T.b[i] = T.k[i] = T.h[i] = 0;
    }
    return 0;
}
posted @ 2023-08-22 09:36  5k_sync_closer  阅读(11)  评论(0编辑  收藏  举报  来源