仓鼠找sugar(倍增LCA)

传送门 洛谷P3398

题目描述

小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n。地下洞穴是一个树形结构。这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d)。他们都会走最短路径。现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友?
小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧!

输入

第一行两个正整数n和q,表示这棵树节点的个数和询问的个数。
接下来n-1行,每行两个正整数u和v,表示节点u到节点v之间有一条边。
接下来q行,每行四个正整数a、b、c和d,表示节点编号,也就是一次询问,其意义如上。

输出

对于每个询问,如果有公共点,输出大写字母“Y”;否则输出“N”。

样例

  • Input
    5 5
    2 5
    4 2
    1 3
    1 4
    5 1 5 1
    2 2 1 4
    4 1 3 4
    3 1 1 5
    3 5 1 4

  • Output
    Y
    N
    Y
    Y
    Y

题解

  • 如果两个仓鼠走的路有交集的话,那么其中一个的LCA一定在另一个路径上。
  • 设a,b的LCA为x,c,d的LCA为y,如果depth[x] > depth[y],x必然在cy或者dy上,即x必然和c、d其中一个点有公共祖先,并且这个点的在x下面;
    同理,如果depth[x] < depth[y],y必然和a、b其中一个有公共祖先,并且这个点在y下面。
    仓鼠找sugar(倍增LCA)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<bits/stdc++.h>
using namespace std;
#define INIT(a,b) memset(a,b,sizeof(a))
const int maxn=1e5+7;
int Begin[maxn],fa[maxn][30],lg[maxn],depth[maxn];
struct Edge{
int to,next;
}ae[maxn<<1];
int tot=0,n,q;
int a,b,c,d;
void Add(int x,int y){
ae[tot]=(Edge){y,Begin[x]};
Begin[x]=tot++;
}
void Dfs(int now,int f){
fa[now][0]=f;
depth[now]=depth[f]+1;
for(int i=1;(1<<i)<=depth[now];i++)
fa[now][i]=fa[fa[now][i-1]][i-1];
for(int i=Begin[now];~i;i=ae[i].next)
if(ae[i].to!=f)Dfs(ae[i].to,now);
}
int Lca(int x,int y){
if(depth[x]<depth[y]) swap(x,y);
while(depth[x]>depth[y])
x=fa[x][lg[depth[x]-depth[y]]-1];
if(x==y) return x;
for(int i=lg[depth[x]];i>=0;i--){
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
}
return fa[x][0];
}
bool Judge(int x,int y){
if(depth[x]<depth[y]) return false;
while(depth[x]>depth[y])
x=fa[x][lg[depth[x]-depth[y]]-1];
if(x==y) return true;
return false;
}
int main(){
INIT(Begin,-1);
scanf("%d %d",&n,&q);
for(int i=0;i<n-1;i++){
scanf("%d%d",&a,&b);
Add(a,b);Add(b,a);
}
for(int i=1;i<=n;i++)
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
Dfs(1,0);
while(q--){
scanf("%d%d%d%d",&a,&b,&c,&d);
int x=Lca(a,b),y=Lca(c,d);
if(depth[x]<depth[y]){
if(Judge(a,y)||Judge(b,y))printf("Y\n");
else printf("N\n");
}
else{
if(Judge(c,x)||Judge(d,x))printf("Y\n");
else printf("N\n");
}
}
return 0;
}