题意:一棵树, A要从a号节点走到b A 要 从 a 号 节 点 走 到 b 号节点, B要从x号节点走到y B 要 从 x 号 节 点 走 到 y 号节点。每次给出一组 (a,b)和(x,y) ( a , b ) 和 ( x , y ) 。问这两条路径是否有重合部分(包括一个点)。
这个问题需要进行分类讨论。首先,如果
lca(a,b)
l
c
a
(
a
,
b
)
的深度大于
x和y
x
和
y
的深度,或者
lca(x,y)
l
c
a
(
x
,
y
)
的深度大于
a和b
a
和
b
的深度,显然都是不行的。
对于两条路径有重合的情况,一定是两个点的
lca
l
c
a
在另外两个点的路径上。如果两条路径有重合部分,就应该是以下的这种情况:这里
p=lca(a,b),q=lca(x,y)
p
=
l
c
a
(
a
,
b
)
,
q
=
l
c
a
(
x
,
y
)
dep[p]>=dep[q]
lca(x,p)=p||lca(y,p)=p;
dep[p]<dep[q]
lca(a,q)=q||lca(b,q)=q
其余的不满足以上两种情况的均为无重合部分。
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
struct node
{
int next,to;
}e[1001000];
int n,q,num,head[1001000];
int dep[1001000],f[500500][25];
void add(int from,int to)
{
e[++num].next=head[from];
e[num].to=to;
head[from]=num;
}
void dfs(int x,int fa)
{
dep[x]=dep[fa]+1;
f[x][0]=fa;
for(int i=1;(1<<i)<=dep[x];++i)
f[x][i]=f[f[x][i-1]][i-1];
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa)
continue;
dfs(v,x);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y])
swap(x,y);
for(int i=20;i>=0;--i)
if(dep[x]-dep[y]>=(1<<i))
x=f[x][i];
if(x==y)
return x;
for(int i=20;i>=0;--i)
{
if(dep[x]>=(1<<i)&&f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int main()
{
cin>>n>>q;
for(int i=1;i<=n-1;++i)
{
int x,y;
cin>>x>>y;
add(x,y);
add(y,x);
}
dfs(1,0);
for(int i=1;i<=q;++i)
{
int a,b,c,d;
cin>>a>>b>>c>>d;
int p=lca(a,b);
int q=lca(c,d);
if(dep[p]>dep[c]&&dep[p]>dep[d])
{
printf("N\n");
continue;
}
if(dep[q]>dep[a]&&dep[q]>dep[b])
{
printf("N\n");
continue;
}
if(dep[p]>=dep[q])
{
if(lca(p,c)==p||lca(p,d)==p)
{
printf("Y\n");
continue;
}
}
if(dep[p]<dep[q])
{
if(lca(q,a)==q||lca(q,b)==q)
{
printf("Y\n");
continue;
}
}
printf("N\n");
}
return 0;
}