P9520 [JOISC 2022 Day1] 监狱 题解

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

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

考虑建图,边 uv 存在当且仅当 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 @   Jijidawang  阅读(13)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示