AT_joisc2022_a 刑務所 (Jail) 题解
若 $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;
}