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的更多相关文章

  1. 【Tarjan】洛谷P3379 Tarjan求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  2. 倍增\ tarjan求lca

    对于每个节点v,记录anc[v][k],表示从它向上走2k步后到达的节点(如果越过了根节点,那么anc[v][k]就是根节点). dfs函数对树进行的dfs,先求出anc[v][0],再利用anc[v ...

  3. 详解使用 Tarjan 求 LCA 问题(图解)

    LCA问题有多种求法,例如倍增,Tarjan. 本篇博文讲解如何使用Tarjan求LCA. 如果你还不知道什么是LCA,没关系,本文会详细解释. 在本文中,因为我懒为方便理解,使用二叉树进行示范. L ...

  4. 倍增 Tarjan 求LCA

                                                                                                         ...

  5. 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 ...

  6. tarjan求lca的神奇

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  7. Tarjan求LCA(离线)

    基本思想 把要求的点对保存下来,在dfs时顺带求出来. 方法 将每个已经遍历的点指向它回溯的最高节点(遍历它的子树时指向自己),每遍历到一个点就处理它存在的询问如果另一个点已经遍历,则lca就是另一个 ...

  8. 图论分支-倍增Tarjan求LCA

    LCA,最近公共祖先,这是树上最常用的算法之一,因为它可以求距离,也可以求路径等等 LCA有两种写法,一种是倍增思想,另一种是Tarjan求法,我们可以通过一道题来看一看, 题目描述 欢乐岛上有个非常 ...

  9. Tarjan求LCA总结

    Tarjan算法向上标记法:从x向上走到根节点,并标记所有经过的点从y向上走到根节点,当第一次遇到已标记的节点时,就找到了LCA(x, y)对于每个询问,向上标记法的时间复杂度最坏为O(n) 在深度遍 ...

随机推荐

  1. PostgreSQL自学笔记:3 数据库的基本操作

    3 数据库的基本操作 3.1 创建数据库 3.1.1 使用对象浏览器创建数据库 [Server] -> PostgreSQL 9.6 -> 数据库,右击 -> 创建 通常: 数据库: ...

  2. Java 多线程 sleep方法与wait方法的区别

    sleep方法会使线程暂停执行一段时间,wait方法会阻塞线程,直到被唤醒或等待时间超时. 两者区别具体如下: 1 原理不同 sleep方法是Thread类的静态方法,使线程暂停执行一段时间,等到计时 ...

  3. PHP文件上传大小限制问题

    一.Thinkphp方面限制  $upload->maxSize   =     31457280 ; //设置附件上传大小 二.七牛方面限制: 'UPLOAD_FILE_QINIU' => ...

  4. vue调用Moment显示时间

    1.下载 Moment 网站: http://momentjs.cn/ 2创建一个vue的文本格式    admin.vue 3.定义给值 代码如下 <template> <div ...

  5. [LeetCode] Generate Random Point in a Circle 生成圆中的随机点

    Given the radius and x-y positions of the center of a circle, write a function randPoint which gener ...

  6. Log4j的入门和使用

    Log4j(log for java)是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI组件,甚至是套接口服务器.NT的事件记录器.UNIX Sy ...

  7. atom编辑器安装插件报错。。

    Checking for native build tools failed gyp info it worked if it ends with ok gyp info using node-gyp ...

  8. mysql 5.7.21 解压版安装配置方法图文教程

    引用:https://www.jb51.net/article/140951.htm 1.首先,你要下载MySQL解压版,下载地址,图解: 2.解压安装包,根据自己的喜好选择路径,我选择的路径是C:\ ...

  9. jmeter使用指南:jmeter无脑式指南

    一:启动jmeter 二:添加线程组 三:添加 HTTP 请求 四:添加监听器 五:填写访问的域名,并保存 六:运行,查看结果 七:配置多线程.循环机制,进行压力测试

  10. java.lang.NoClassDefFoundError: com/sun/image/codec/jpeg/JPEGCodec

    java.lang.NoClassDefFoundError: com/sun/image/codec/jpeg/JPEGCodec 这个类在 rt.jar 里面 本地开发,jre里有这个包,所以不会 ...