在一颗有根树中,给定两个节点,找到他们两个最近的公共祖先(为保证统一性,结点本身也为其祖先)
从一个点向他的根节点走,经过的所有点都标记一下,再走第二个点,如果走到被标记的点即位二者的最近公共祖先
预处理 O(nlogn)
01
f[i,j]数组表示:节点i向上跳2^j步到达的点
if(j==0) f[i,j]=i的父节点
if(j>0) f[i,j]=f[f[i,j-1],j-1]
02
depth[i]数组表示:节点i的层数,即到根节点的距离+1查询 O(logn)
【1】 让两个点跳到同一层
【2】 让两个点同时跳,直到跳到两个点的最近公共祖先的下一层
给定一棵包含 n个节点的有根无向树,节点编号互不相同,但不一定是 1∼n。有 m
个询问,每个询问给出了一对节点的编号 x 和 y,询问 x 与 y的祖孙关系。
输入格式
输入第一行包括一个整数 表示节点个数;
接下来 n行每行一对整数 a 和 b,表示 a 和 b 之间有一条无向边。如果 b 是 −1,那么 a
就是树的根;
第 n+2行是一个整数 m表示询问个数;
接下来 m行,每行两个不同的正整数 x 和 y,表示一个询问。
输出格式
对于每一个询问,若 x是 y 的祖先则输出 1,若 y 是 x 的祖先则输出 2,否则输出 0
数据范围
1≤n,m≤4×104
1≤每个节点的编号≤4×104
输入样例:
- 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
- 0
- 0
- 0
- 2
- #include
- #include
- #include
- #include
-
- using namespace std;
- const int N=4e4+10;
-
- int n,m;
- int h[N],e[2*N],ne[2*N],idx;
- int f[N][16];//i号结点向上跳2^j步到达的结点编号
- int depth[N];//i号结点的层数
-
- void add(int a,int b)
- {
- e[idx]=b,ne[idx]=h[a],h[a]=idx++;
- }
-
- void bfs(int root)
- {
- memset(depth,0x3f3f3f,sizeof depth);
-
- depth[0]=0,depth[root]=1;
- // 哨兵depth[0] = 0: 如果从i开始跳2^j步会跳过根节点
- // fa[fa[j][k-1]][k-1] = 0
- // 那么fa[i][j] = 0 depth[fa[i][j]] = depth[0] = 0
-
- queue<int> q;
- q.push(root);
- while(!q.empty())
- {
- int t=q.front();
- q.pop();
- for(int i=h[t];~i;i=ne[i])
- {
- int j=e[i];
- if(depth[j]>depth[t]+1)
- {
- depth[j]=depth[t]+1;
- q.push(j);
- f[j][0]=t;
-
- for(int k=1;k<=15;k++)
- {
- f[j][k]=f[f[j][k-1]][k-1];
- }
- }
- }
- }
- }
-
- int lca(int a,int b)
- {
- if(depth[a]
swap(a,b); -
- //让两个点跳到同一层
- for(int k=15;k>=0;k--)
- {
- if(depth[f[a][k]]>=depth[b])
- a=f[a][k];
- }
- //让两个点同时跳,直到跳到两个点的最近公共祖先的下一层
- if(a==b) return a;
- for(int k=15;k>=0;k--)
- {
- if(f[a][k]!=f[b][k])
- {
- a=f[a][k];
- b=f[b][k];
- }
- }
-
- return f[a][0];
- }
-
- int main()
- {
- cin>>n;
- int root=0;
- memset(h,-1,sizeof h);
- for(int i=1;i<=n;i++)
- {
- int a,b;
- scanf("%d%d",&a,&b);
- if(b==-1) root=a;
- else
- {
- add(a,b);
- add(b,a);
- }
- }
-
- bfs(root);//预处理出f[][],depth[]数组
-
- cin>>m;
- while (m -- )
- {
- int a,b;
- scanf("%d%d",&a,&b);
- int q=lca(a,b);
- if(q==a) cout<<1<
- else if(q==b) cout<<2<
- else cout<<0<
- }
- return 0;
- }
-
相关阅读:
通过FNN算法进行特征组合的商品推荐详细教程 有代码+数据
【第二章 数据的表示和运算】d1
缓存热key问题
NLP 03(LSTM)
洛谷刷题笔记 确定进制
在浏览器中运行 TensorFlow.js 来训练模型并给出预测结果(Iris 数据集)
01、前言
抖音预约服务小程序开发:前端与后端技术的完美融合
JavaSE入门--初始Java
AOT漫谈专题(第五篇): 如何劫持.NET AOT编译器 进行源码级调试
-
原文地址:https://blog.csdn.net/weixin_62224014/article/details/127579499