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) 在深度遍 ...
随机推荐
- 将ActiveX打包成CAB发布的注意事项
1.在实现ActiveX组件时,注意VS必须使用管理员身份运行,否则会提示不成功 2.在解决方案中添加一个安装项目 a.在View中点击文件系统,添加对ActiveX项目的输出 b.注册表HKEY_C ...
- 使用Callable接口创建线程和使用线程池的方式创建线程
1.使用Callable接口的方式实现多线程,这是JDK5.0新增的一种创建多线程的方法 package com.baozi.java2; import java.util.concurrent.Ca ...
- 转摘: MySQL详解--锁
原文 http://blog.csdn.net/xifeijian/article/details/20313977 InnoDB锁问题 InnoDB与MyISAM的最大不同有两点:一是支持事务(TR ...
- Spring-day03
Spring集成JDBC:提供了一些方便我们使用JDBC的工具类; query(String,ResultSetHandler handler,Object..parm){ Connection co ...
- 秒杀ecshop的前台写shell 0day
ECSHOP号称最大的开源网店系统,官方是这样介绍它的:“ECShop网店系统是一套免费开源的网上商店软件,无论在稳定性.代码优化.运行效率.负载能力.安全等级.功能可操控性和权限严密性等方面都居国内 ...
- 构建Dubbo-2.0.7源码
一. 下载源码: git clone --branch dubbo-2.0.7 https://github.com/apache/incubator-dubbo.git 二. 下载依赖 git cl ...
- 电子产品使用感受之-- AirPods + Apple Watch S4 = Smart iPod ?
- eclipse maven工程打包失败
报错如下: Maven install失败 Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:comp ...
- 推荐一个Monokai风格的EditPlus配色方案
如何配置 找到EditPlus的配置文件editplus_u.ini,该文件默认在:系统盘:\Users\用户名\AppData\Roaming\EditPlus目录中.将其中的内容替换为如下即可: ...
- 学习懈怠的时候,可以运行Qt自带的Demo,或者Delphi控件自带的Demo,或者Cantu书带的源码,运行一下Boost的例子(搞C++不学习Boost/Poco/Folly绝对是一大损失,有需要使用库要第一时间想到)(在六大的痛苦经历说明,我的理论性确实不强,更适合做实践)
这样学还不用动脑子,而且熟悉控件也需要时间,而且慢慢就找到感觉了,就可以精神抖擞的恢复斗志干活了.或者Cantu书带的源码. 并且可以使用Mac SSD运行Qt的Demo,这样运行速度快一点. 此外, ...