2021.8.10提高B组模拟2T2 祖孙询问(lca)(倍增)

Posted SSL_LKJ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021.8.10提高B组模拟2T2 祖孙询问(lca)(倍增)相关的知识,希望对你有一定的参考价值。

祖孙询问

题目大意

已知一棵n个节点的有根树。有m个询问。每个询问给出了一对节点的编号x和y,询问x与y的祖孙关系。

输入样例

输入第一行包括一个整数n表示节点个数。

接下来n行每行一对整数对a和b表示a和b之间有连边。如果b是-1,那么a就是树的根。

第n+2行是一个整数m表示询问个数。

接下来m行,每行两个正整数x和y。

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

输出样例

对于每一个询问,输出1:如果x是y的祖先,输出2:如果y是x的祖先,否则输出0。

1
0
0
0
2

题目数据

对于100%的.据,n,m≤40000,每个节点的编号都不超过40000。

解题思路

建出一棵树

在树上跑 lca(最近公共祖先)

如果 x,y 的 lca 为 x ,则 x 是 y 的祖先

lca 为 y,则 y 是 x 的祖先

否则为0

注:记得用倍增优化

AC代码

#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
int n,m,k,nn,tot,f[40005][20],deep[40005],head[40005];
struct node
{
	int to,next;
}a[80005];
void add(int x,int y)
{
	a[++tot]=(node){y,head[x]};
	head[x]=tot;
}
void dfs(int x)//先弄出来树,每个节点的深度
{
	for(int i=head[x];i;i=a[i].next)
	{
		deep[a[i].to]=deep[x]+1;
		dfs(a[i].to);
	}
}
int lca(int x,int y)//lca
{
	int ans;
	if(deep[x]<deep[y])ans=1,swap(x,y);
	else 
	{
		if(deep[x]>deep[y])ans=2;
		else return 0;
	}
	for(int i=nn;i>0;i--)
		if(deep[f[x][i]]>=deep[y])
			x=f[x][i];
	if(x!=y)return 0;
	return ans;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		if(y==-1)k=x;
		else f[x][1]=y,add(y,x);
	}
	deep[k]=1;
	dfs(k);
	nn=log2(n)+1;//预处理
	for(int j=2;j<=nn;j++)
		for(int i=1;i<=40000;i++)
			f[i][j]=f[f[i][j-1]][j-1];
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%d\\n",lca(x,y));
	}
	return 0;
}

谢谢

以上是关于2021.8.10提高B组模拟2T2 祖孙询问(lca)(倍增)的主要内容,如果未能解决你的问题,请参考以下文章

2021.7.13提高B组模拟2T2 JIH的玩偶(倍增)

Jzoj 3054NOIP2012模拟10.27倍增祖孙询问

2021.8.10提高B组模拟2T1 单峰(快速幂)

2021.8.10提高B组模拟2T1 单峰(快速幂)

2021.8.10提高B组模拟2T4 数字(dp)

2021.8.10提高B组模拟2T3 比赛(二分)(贪心—前缀和)