最近公共祖先-LCA
题目描述
时间限制:1.2s 内存限制:256.0MB
问题描述
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入格式
第一行包含三个正整数\(N\),\(M\),\(S\),分别表示树的结点个数、询问的个数和树根结点的序号。
接下来\(N-1\)行每行包含两个正整数\(x\),\(y\) ,表示\(x\)结点和\(y\)结点之间有一条直接连接的边(数据保证可以构成树)。
接下来\(M\)行每行包含两个正整数\(a\),\(b\),表示询问\(a\)结点和\(b\)结点的最近公共祖先。
输出格式
输出包含\(M\)行,每行包含一个正整数,依次为每一个询问的结果。
样例输入
5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5
样例输出
4
4
1
4
4
数据规模和约定
对于\(30%\)的数据,\(N<=10\),\(M<=10\)。
对于\(70%\)的数据,\(N<=10000\),\(M<=10000\)。
对于\(100%\)的数据,\(N<=500000\),\(M<=500000\)。
注意
这道题里一个节点的祖先是包括自己的
解析
1.暴力(70分)
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
vector<int> a[500005];
int deep[500005], father[500005];
void dfs(int cur, int par) { // 用dfs遍历数
father[cur] = par; // 存父亲节点
deep[cur] = deep[par] + 1; // 存深度
for (int i = 0; i < a[cur].size(); i++)
if (a[cur][i] != par)
dfs(a[cur][i], cur);
}
int find(int x, int y) { // 寻找两个节点的直接最近公共祖先
// 若两个节点的深度不同,先让两个节点深度相等,再一起向上寻找祖先
if (deep[x] < deep[y]) swap(x, y);
while (deep[x] > deep[y]) x = father[x];
while (x != y) x = father[x], y = father[y];
return x;
}
int main(int argc, char** argv) {
int n, m, s, x, y; cin >> n >> m >> s;
for (int i = 0; i < n - 1; i++) {
cin >> x >> y;
a[x].push_back(y);
a[y].push_back(x);
}
dfs(s, 0);
for (int i = 0; i < m; i++) {
cin >> x >> y;
cout << find(x, y) << endl;
}
return 0;
}
2.优化
首先我们发现主要影响速度的就是find函数
可以分成两段,并齐深度和共同向上找这两个部分
并齐深度:
我们是知道x需要向上的次数,也就是deep[x] - deep[y]次
可以运用二进制的思想来减少询问次数
定义数组f[i][t]为i节点向上寻找2^t个的祖先
处理数组用递推的形式表示出来
f[i][0] = father[i];
f[i][j] = f[f[i][j - 1]][j - 1];
当然,会出现找到的祖先以超过根节点这种问题,可以将根节点s的祖先定位它本身
可将deep[x] - deep[y]转化为二进制形式,bin[n]若为1,表示向上询问对应的次数
向上寻找祖先:
t从19到0
每次询问x与y向上2^t的公共祖先是否相同
若不相同时退出循环x的父节点则是x与y的最近公共祖先
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
vector<int> a[500005];
int deep[500005], father[500005];
int f[500005][25];
int n, s;
void dfs(int cur, int par) {
father[cur] = par;
deep[cur] = deep[par] + 1;
for (int i = 0; i < a[cur].size(); i++)
if (a[cur][i] != par)
dfs(a[cur][i], cur);
}
void init() {
for (int i = 1; i <= n; i++)
f[i][0] = father[i];
for (int j = 1; j <= 19; j++)
for (int i = 1; i <= n; i++)
f[i][j] = f[f[i][j - 1]][j - 1];
}
int find(int x, int y) {
if (deep[x] < deep[y]) swap(x, y);
int w = 0, N = deep[x] - deep[y];
while (N) {
if (N % 2 == 1) x = f[x][w];
N /= 2;
w++;
}
if (x == y) return x;
for (int t = 19; t >= 0; t--){
if (f[x][t] != f[y][t])
x = f[x][t], y = f[y][t];
}
return father[x];
}
int main(int argc, char** argv) {
ios::sync_with_stdio(false);
int m, x, y; cin >> n >> m >> s;
for (int i = 0; i < n - 1; i++) {
cin >> x >> y;
a[x].push_back(y);
a[y].push_back(x);
}
dfs(s, s); init();
for (int i = 0; i < m; i++) {
cin >> x >> y;
cout << find(x, y) << endl;
}
return 0;
}
最近公共祖先-LCA的更多相关文章
- Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)
Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...
- POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)
POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...
- POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)
POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...
- [模板] 最近公共祖先/lca
简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...
- 【lhyaaa】最近公共祖先LCA——倍增!!!
高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...
- POJ 1470 Closest Common Ancestors (最近公共祖先LCA 的离线算法Tarjan)
Tarjan算法的详细介绍,请戳: http://www.cnblogs.com/chenxiwenruo/p/3529533.html #include <iostream> #incl ...
- 【Leetcode】查找二叉树中任意结点的最近公共祖先(LCA问题)
寻找最近公共祖先,示例如下: 1 / \ 2 3 / \ / \ 4 5 6 7 / \ ...
- 最近公共祖先LCA(Tarjan算法)的思考和算法实现
LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现 小广告:METO CODE 安溪一中信息学在线评测系统(OJ) //由于这是第一篇博客..有点瑕疵...比如我把false写成了f ...
- 查找最近公共祖先(LCA)
一.问题 求有根树的任意两个节点的最近公共祖先(一般来说都是指二叉树).最近公共祖先简称LCA(Lowest Common Ancestor).例如,如下图一棵普通的二叉树. 结点3和结点4的最近公共 ...
- 最近公共祖先(LCA)的三种求解方法
转载来自:https://blog.andrewei.info/2015/10/08/e6-9c-80-e8-bf-91-e5-85-ac-e5-85-b1-e7-a5-96-e5-85-88lca- ...
随机推荐
- 1091. Tmutarakan Exams
1091. Tmutarakan Exams Time limit: 1.0 secondMemory limit: 64 MB University of New Tmutarakan trains ...
- Attention Is All You Need
目录 概 主要内容 Positional Encoding auto_regressive 额外的细节 代码 Vaswani A., Shazeer N., Parmar N., Uszkoreit ...
- [opencv]keypoint数据结构分析
KeyPoint这数据结构中有如下数据成员: angle:角度,表示特征点的方向,通过Lowe大神的论文可以知道,为了保证方向不变形,SIFT算法通过对特征点周围邻域进行梯度运算,求得该点方向.-1为 ...
- spring练习,使用Eclipse搭建的Spring开发环境,属性注入通过构造方法方式实现,模拟用户的正常登录。
相关 知识 >>> 相关 练习 >>> 实现要求: 使用Eclipse搭建的Spring开发环境,属性注入通过构造方法方式实现,模拟用户的正常登录.要求如下: 通过 ...
- Spring Boot 整合 Fisco Bcos(区块链)
简介 FISCO BCOS是由国内企业主导研发.对外开源.安全可控的企业级金融联盟链底层平台,由金链盟开源工作组协作打造,并于2017年正式对外开源. 目前,成熟的区块链的平台不少,之所以选择FISC ...
- 造轮子-strace(二)实现
这一篇文章会介绍strace如何工作,再稍微深入介绍一下什么是system call.再介绍一下ptrace.wait(strace依赖的system call).最后再一起来造个轮子,动手用代码实现 ...
- Kubernetes-Kuboard
前言 本篇是Kubernetes第十五篇,大家一定要把环境搭建起来,看是解决不了问题的,必须实战. Kubernetes系列文章: Kubernetes介绍 Kubernetes环境搭建 Kubern ...
- pycharm debug调试模式报“UnicodeDecodeError:'gdk' codec can't decode byte 0xac”,无法正常调试
遇到的问题: 本机python 3.8 pycharn 3.4.4 运行代码的时候,选择debug模式,提示"UnicodeDecodeError:'gdk' codec can't dec ...
- [ Flask ] myblog_flask问题集(RESTfull风格)
VUE问题 前端VUE怎么捕获所有404NOT FOUND的路由呢? [ 解决方案 ] vue-router路由守卫,参考文档:动态路由匹配 对于路由.../edit/<id>,自己能编辑 ...
- vue部署服务器以及解决部署到apache路由出现404
最近在开发cms的时候使用Vue.js框架,利用vue-route.vue-cli结合webpack编写了一个单页路由项目,自己在服务器端配置apache.部署完成后,访问没问题,从页面中点击跳转就会 ...