Tarjan求LCA
LCA问题算是一类比较经典的树上的问题
做法比较多样
比如说暴力啊,倍增啊等等
今天在这里给大家讲一下tarjan算法!
tarjan求LCA是一种稳定高速的算法
时间复杂度能做到预处理O(n + m),查询O(1)
它的主要思想是dfs和并查集
1.输入数据,找出根节点(或输入的)并将图存起来
2.输入需要查找的每一对点(两个点),也存起来(也存成图)
3.从根节点开始向它的每一个孩子节点进行深搜
4.同时开一个bool类型的数组记录此节点是否搜索过
5.搜索到p节点时先将p标记为已经搜索过了
6.然后遍历所有与p相连的节点,并标记为已经搜索过了
7.接着将p的子节点和p合并(此处要用到并查集)
8.然后遍历所有和p有询问关系的p的子节点
9.若该子节点已经遍历过,则一定可以将该子节点和p的父亲节点合并
可能还是有很多人并没有完全理解这段文字叙述的算法过程
下面就直接上代码(注释很详细)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<string>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 5e5 + ;
int read()
{
int ans = , op = ;
char ch = getchar();
while(ch < '' || ch > '')
{
if(ch == '-') op = -;
ch = getchar();
}
while(ch >= '' && ch <= '')
{
ans *= ;
ans += ch - '';
ch = getchar();
}
return ans * op;
}
struct Drug
{
int next, to, lca;
}edge[maxn<<], qedge[maxn<<];//edge[N]为树的链表;qedge[N]为需要查询LCA的两节点的链表
int n, m, s, x, y;
int num_edge, num_qedge, head[maxn], qhead[maxn], father[maxn];
bool visit[maxn];//判断是否被找过
void add_edge(int from, int to)//建立树的链表
{
edge[++num_edge].next = head[from];
edge[num_edge].to = to;
head[from] = num_edge;
// printf("#%d #%d #%d #%d\n", num_edge, head[from], from, edge[num_edge].next);
}
void add_qedge(int from, int to)//建立需要查询LCA的两节点的链表
{
qedge[++num_qedge].next = qhead[from];
qedge[num_qedge].to = to;
qhead[from] = num_qedge;
}
int find(int x)//找爹函数
{
if(father[x] ^ x) father[x] = find(father[x]);
return father[x];
}
void dfs(int x)//把整棵树的一部分看作以节点x为根节点的小树, x的初始值为s;
{
father[x] = x;//由于节点x被看作是根节点,所以把x的father设为它自己
visit[x] = ;//标记为已被搜索过
for(int k = head[x]; k ; k=edge[k].next)//遍历所有与x相连的节点
{
if(!visit[edge[k].to])//若未被搜索
{
dfs(edge[k].to);//以该节点为根节点搞小树
father[edge[k].to] = x;//把x的孩子节点的father重新设为x
}
}
for(int k = qhead[x]; k ; k = qedge[k].next)//搜索包含节点x的所有询问
{
if(visit[qedge[k].to])//如果另一节点已被搜索过
{
qedge[k].lca = find(qedge[k].to);
//把另一节点的祖先设为这两个节点的最近公共祖先
if(k & ) qedge[k + ].lca = qedge[k].lca;
//由于将每一组查询变为两组,所以2n-1和2n的结果是一样的
else qedge[k - ].lca = qedge[k].lca;
}
}
}
int main(){
n = read(), m = read(), s = read();//输入节点数,查询数和根节点
for(int i = ;i < n;i++)
{
x = read(), y = read();//输入每条边
add_edge(x, y);
add_edge(y, x);
}
for(int i = ;i <= m;i++)
{
x = read(), y = read();
//输入每次查询,考虑(u,v)时若查找到u但v未被查找,所以将(u,v)(v,u)全部记录
add_qedge(x, y);
add_qedge(y, x);
}
dfs(s);
for(int i = ;i <= m;i++) printf("%d\n", qedge[i << ].lca);//两者结果一样,只输出一组即可
// printf("%d", num_edge);
return ;
}
Tarjan求LCA的更多相关文章
- 【Tarjan】洛谷P3379 Tarjan求LCA
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 倍增\ tarjan求lca
对于每个节点v,记录anc[v][k],表示从它向上走2k步后到达的节点(如果越过了根节点,那么anc[v][k]就是根节点). dfs函数对树进行的dfs,先求出anc[v][0],再利用anc[v ...
- 详解使用 Tarjan 求 LCA 问题(图解)
LCA问题有多种求法,例如倍增,Tarjan. 本篇博文讲解如何使用Tarjan求LCA. 如果你还不知道什么是LCA,没关系,本文会详细解释. 在本文中,因为我懒为方便理解,使用二叉树进行示范. L ...
- 倍增 Tarjan 求LCA
...
- SPOJ 3978 Distance Query(tarjan求LCA)
The traffic network in a country consists of N cities (labeled with integers from 1 to N) and N-1 ro ...
- tarjan求lca的神奇
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- Tarjan求LCA(离线)
基本思想 把要求的点对保存下来,在dfs时顺带求出来. 方法 将每个已经遍历的点指向它回溯的最高节点(遍历它的子树时指向自己),每遍历到一个点就处理它存在的询问如果另一个点已经遍历,则lca就是另一个 ...
- 图论分支-倍增Tarjan求LCA
LCA,最近公共祖先,这是树上最常用的算法之一,因为它可以求距离,也可以求路径等等 LCA有两种写法,一种是倍增思想,另一种是Tarjan求法,我们可以通过一道题来看一看, 题目描述 欢乐岛上有个非常 ...
- Tarjan求LCA总结
Tarjan算法向上标记法:从x向上走到根节点,并标记所有经过的点从y向上走到根节点,当第一次遇到已标记的节点时,就找到了LCA(x, y)对于每个询问,向上标记法的时间复杂度最坏为O(n) 在深度遍 ...
随机推荐
- js实现数组去重的几种方法
1.简单结构的数组,例如[1,2,3,3,4],使用es6提供的Set和Array.from Set:是一种新的数据结构,可以接收一个数组或者是类数组对象,自动去重其中的重复项目. 类数组对象:只包含 ...
- BOM 浏览器对象模型_当前窗口的浏览历史 history 对象
当前窗口的浏览历史 window.history 对象 保存了当前窗口访问过的所有页面网址 由于安全原因,浏览器不允许脚本读取这些地址,但是允许在地址之间导航 history.back() 相当于 h ...
- apache启动不了应对方法
原因一:80端口占用 例如IIS,另外就是迅雷.我的apache服务器就是被迅雷害得无法启用! 原因二:软件冲突 装了某些软件会使apache无法启动如Dr.com 你打开网络连接->TcpIp ...
- Spring-day02
Annotation复习:1,Annotation:作为类型的元数据; 1,给类型加标记; 2,annotation可以添加各种类型的属性;2,Annotation的上的标记: 1),target:标 ...
- python dgango简介 安装 多表查询
一.socket服务器 import socket sk=socket.socket() sk.bind(("127.0.0.1",8890)) sk.listen() while ...
- hive高级数据类型
hive的高级数据类型主要包括:数组类型.map类型.结构体类型.集合类型,以下将分别详细介绍. 1)数组类型 array_type:array<data_type> -- 建表语句 cr ...
- 【OJ】抓牛问题
/* 农夫John的奶牛跑路了.将地图视作一条数轴,John的初始位置在s而奶牛的位置在t(0<=s,t<=100000).John可以花费一分钟的时间使自己作如下移动: 1 从点x移动到 ...
- vueX、vue中transition的使用、axios
引入一篇好文章链接:看一遍就会的vuex文章;完!!! vue中transtion的使用:transition文章;完!!! axios的文章:axios;完!!!
- Python002-操作MSSQL(Microsoft sql server)基础示例(二)
前文http://www.cnblogs.com/fengpingfan/p/7675291.html,讲述了python操作mssql的步骤.环境创建.常用方法等,本文将实例演示python操作ms ...
- 6、jeecg 笔记之 自定义excel 模板导出(一)
1.前言 jeecg 中已经自带 excel 的导出导出功能,其所使用的是 easypoi,尽管所导出的 excel 能满足大部分需求, 但总是有需要用到自定义 excel 导出模板,下文所用到的皆是 ...