题目
Description
已知一棵n个节点的有根树。有m个询问。每个询问给出了一对节点的编号x和y,询问x与y的祖孙关系。
Input
输入第一行包括一个整数n表示节点个数。
接下来n行每行一对整数对a和b表示a和b之间有连边。如果b是-1,那么a就是树的根。
第n+2行是一个整数m表示询问个数。
接下来m行,每行两个正整数x和y。
Output
对于每一个询问,输出1:如果x是y的祖先,输出2:如果y是x的祖先,否则输出0。
Sample Input
10
234 -1
12 234
13 234
14 234
15 234
16 234
17 234
18 234
19 234
233 19
5
234 233
233 12
233 13
233 15
233 19
Sample Output
1
0
0
0
2
HINT
对于30%的数据,nm≤1000。
对于100%的数据n,m≤40000,每个节点的编号都不超过40000。
TJ
Think
求x or y是否是y or x的祖先,第一时间是求LCA(x,y)
,因为如果一个节点是另一个节点的祖先,那么这两个节点的LCA一定等于是另一个节点的祖先的节点。
所以只需要判断:
{
1
(
L
C
A
(
x
,
y
)
=
y
)
2
(
L
C
A
(
x
,
y
)
=
x
)
0
(
L
C
A
(
x
,
y
)
≠
x
≠
y
)
\left\{\begin{matrix} &\\1 (LCA(x,y)=y) & \\2 (LCA(x,y)=x) & \\0 (LCA(x,y)\ne x \ne y) \end{matrix}\right.
⎩
⎨
⎧1(LCA(x,y)=y)2(LCA(x,y)=x)0(LCA(x,y)=x=y)
Code
#include<bits/stdc++.h>
using namespace std;
const int N=4e4+5;
int n;
vector<int>v[N];
int dep[N],f[N][20];
void bfs(int x){
memset(dep,0x3f,sizeof dep);
dep[0]=0;
dep[x]=1;
queue<int>q;
q.push(x);
while(!q.empty()){
int t=q.front();
q.pop();
for(auto j:v[t]){
if(dep[j]>dep[t]+1){
dep[j]=dep[t]+1;
q.push(j);
f[j][0]=t;
for(int k=1;k<=19;k++){
f[j][k]=f[f[j][k-1]][k-1];
}
}
}
}
}
int lca(int a,int b){
if(dep[a]<dep[b])swap(a,b);
for(int k=19;k>=0;k--){
if(dep[f[a][k]]>=dep[b]){
a=f[a][k];
}
}
if(a==b)return a;
for(int k=19;k>=0;k--){
if(f[a][k]!=f[b][k]){
a=f[a][k];
b=f[b][k];
}
}
return f[a][0];
}
int m,root;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
int a,b;
cin>>a>>b;
if(b==-1)root=a;
v[a].push_back(b);
v[b].push_back(a);
}
bfs(root);
cin>>m;
while(m--){
int a,b;
cin>>a>>b;
if(lca(a,b)==a)cout<<"1\n";
else if(lca(a,b)==b)cout<<"2\n";
else cout<<"0\n";
}
return 0;
}