[Luogu 3398] 仓鼠找sugar
又是 LCA…
前两天死活写不过的一个题今天终于顺手切了。
思路嘛参考了一楼题解。
就是说,对于 a
, b
, c
, d
四个点,
令 x
= LCA(a, b), y
= LCA(c, d),
两条路径有交叉,当且仅当 c
, d
至少一个在 x
的子树下,且 a
, b
至少一个在 y
的子树下。
由于我是 HLD 求的 LCA,第一遍 DFS 时顺手把子树大小求了,后边判断在不在一棵子属下的时候就可以很方便了。
就这样。
#include <algorithm>
#include <cstdio>
const int MAXN = 100010;
int n, q;
struct Graph
{
struct Edge
{
int to;
Edge *next;
Edge(int to, Edge* next): to(to), next(next) {}
~Edge(void)
{
if(next != NULL)
delete next;
}
}*head[MAXN];
Graph(int n)
{
std :: fill(head + 1, head + n + 1, (Edge*)NULL);
}
~Graph(void)
{
for(int i = 1; i <= n; ++i)
delete head[i];
}
void AddEdges(int u, int v)
{
head[u] = new Edge(v, head[u]);
head[v] = new Edge(u, head[v]);
}
}*G;
namespace HLD
{
int num;
struct Node
{
int depth, father, son, top, size, DFN;
}s[MAXN];
void DFS1(int u, int k)
{
s[u].depth = k;
s[u].size = 1;
int v;
for(Graph :: Edge *i = G -> head[u]; i != NULL; i = i -> next)
if(!s[v = i -> to].size)
{
DFS1(v, k + 1);
s[u].size += s[v].size;
s[v].father = u;
if(s[v].size > s[s[u].son].size)
s[u].son = v;
}
}
void DFS2(int u, int top)
{
s[u].top = top;
s[u].DFN = ++num;
if(s[u].son)
DFS2(s[u].son, top);
int v;
for(Graph :: Edge *i = G -> head[u]; i != NULL; i = i -> next)
if(!s[v = i -> to].DFN)
DFS2(v, v);
}
void Init(void)
{
DFS1(1, 1);
DFS2(1, 1);
}
int LCA(int x, int y)
{
int a, b;
while((a = s[x].top) ^ (b = s[y].top))
if(s[a].depth > s[b].depth)
x = s[a].father;
else
y = s[b].father;
return s[x].depth < s[y].depth ? x : y;
}
bool Range(int x, int y)
{
return s[x].DFN <= s[y].DFN && s[y].DFN < s[x].DFN + s[x].size;
}
bool Query(int a, int b, int c, int d)
{
int x = LCA(a, b), y = LCA(c, d);
return (Range(x, c) || Range(x, d)) && (Range(y, a) || Range(y, b));
}
}
int main(void)
{
scanf("%d %d", &n, &q);
G = new Graph(n);
for(int i = 1, u, v; i < n; ++i)
{
scanf("%d %d", &u, &v);
G -> AddEdges(u, v);
}
HLD :: Init();
for(int i = 1, a, b, c, d; i <= q; ++i)
{
scanf("%d %d %d %d", &a, &b, &c, &d);
puts(HLD :: Query(a, b, c, d) ? "Y" : "N");
}
return 0;
}
谢谢阅读。