版权声明:~~~感谢支持! https://blog.csdn.net/qq_39897867/article/details/88363339
题目
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。
解题思路
就像zyc所言,一道水题。
可以用倍增lca来做。
代码
#include<cstdio>
#include<algorithm>
#include<queue>
#include<string>
#define rr register
using namespace std;
const int t=20;
struct node{
int y,next;
}a[40010];
int n,d[40010],f[40010][31],head[40010],cnt,g,h;
queue<int>q;
void add(int x,int y){
a[++cnt]=(node){y,head[x]}; head[x]=cnt;
}
int read(){
int p=0,f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();}
while (isdigit(c)) p=(p<<3)+(p<<1)+c-48,c=getchar();
return p*f;
}
void bfs(){
while(!q.empty()){
int x=q.front(); q.pop();
for(rr int i=head[x];i;i=a[i].next){
int y=a[i].y;
f[y][0]=x; q.push(y);
d[y]=d[x]+1;
for (rr int j=1;j<=t;j++)
f[y][j]=f[f[y][j-1]][j-1];
}
}
}
int lca(int x,int y){
if (d[y]<d[x]) h=x,x=y,y=h;
for (rr int i=t;i>=0;i--)
if (d[f[y][i]]>=d[x]&&f[y][i]!=0) y=f[y][i];
if (x==y) return x;
for (rr int i=t;i>=0;i--)
if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
int main(){
n=read(); int x,y;
for (rr int i=1;i<=n;i++){
x=read(),y=read();
if (y==-1) q.push(x),d[x]=1; else add(y,x);
}
bfs();
g=read();
for (rr int i=1;i<=g;i++){
x=read(),y=read();
int z=lca(x,y);
if (z==x) printf("1\n"); else
if (z==y) printf("2\n"); else
printf("0\n");
}
}