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)(倍增)的主要内容,如果未能解决你的问题,请参考以下文章