[jzoj 3054] 祖孙询问 {lca}

版权声明:~~~感谢支持! 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"); 
	} 
}

猜你喜欢

转载自blog.csdn.net/qq_39897867/article/details/88363339
lca
今日推荐