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) 在深度遍 ...
随机推荐
- SVN服务器搭建及使用
.SVN(全称Subversion)是优秀的版本控制工具,与微软的TFS相比,有如下优势:开源(免费),支持多种操作系统. 本次我搭建的服务器采用:VisualSVN-Server-3.6.1-x64 ...
- HttpHandler和ashx使用Session 出现未初始化异常
原因: HttpHandler和ashx要实现IRequiresSessionState接口才能访问Session信息 接口IRequiresSessionState: 指定目标 HTTP 处理程序需 ...
- MySQL性能分析及explain的使用(转)
1.使用explain语句去查看分析结果,如 explain select * from test1 where id=1; 会出现: id selecttype table type possibl ...
- Java数据库连接与查询
9个步骤: 1.加载数据库驱动: 2.连接数据库: 3.创建语句statement: 5.创建sql语法字符串: 6.执行: 7.如果步骤6是执行新增.修改.删除操作那么返回的是影响的行数,如果是执行 ...
- (70)Wangdao.com第十一天_JavaScript 日期对象 Date
日期对象 Date 表示一个时间 Date 对象是 JavaScript 原生的时间库 它以1970年1月1日00:00:00作为时间的零点,可以表示的时间范围是前后各1亿天(单位为毫秒) 时间零点( ...
- [LeetCode] Encode N-ary Tree to Binary Tree 将N叉树编码为二叉树
Design an algorithm to encode an N-ary tree into a binary tree and decode the binary tree to get the ...
- [LeetCode] Construct Quad Tree 建立四叉树
We want to use quad trees to store an N x N boolean grid. Each cell in the grid can only be true or ...
- Oracle视图 create View
视图是一种虚表,使用CREATE VIEW语句来定义视图,该视图是基于一个或多个表或视图的逻辑表.一个视图本身不包含任何数据, 视图所基于的表称为基表. 视图就相当于一条select 语句,定义了一个 ...
- 泡泡一分钟:Cooperative Object Transportation by Multiple Ground and Aerial Vehicles: Modeling and Planning
张宁 Cooperative Object Transportation by Multiple Ground and Aerial Vehicles: Modeling and Planning 多 ...
- Python001-操作MSSQL(Microsoft sql server)基础示例(一)
Python操作mssql server数据库可以通过pymssql或pyodbc实现的.此文以pymssql为例.Python操作MSSQL基本操作步骤如下所示: 获取数据库连接Connection ...