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. exit()

    exit()通常是用在子程序中用来终结程序用的,使用后程序自动结束,跳回操作系统. exit(0) 表示程序正常退出,exit⑴/exit(-1)表示程序异常退出. exit() 结束当前进程/当前程 ...

  2. idea使用配置

    一,打开窗口多行显示, Window→Editor Tabs→Tabs Placement→Show Tabs in Single Row 取消选中后即可在多行显示 2 .还可以自行设置打开文件窗口数 ...

  3. [LeetCode] Sliding Puzzle 滑动拼图

    On a 2x3 board, there are 5 tiles represented by the integers 1 through 5, and an empty square repre ...

  4. myeclipse使用git图文教程

    Git介绍与使用 1.什么是Git Git是分布式版本控制系统 Git是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. 2.集中式版本控制系统(CVS / SVN等) 集中 ...

  5. viewport的故事(二)

     挑重点的翻译 自原文 https://www.quirksmode.org/mobile/viewports2.html   在这一页我们将聊一聊移动端的浏览器.   移动端的问题   最明显的问题 ...

  6. centos下静默安装oracle11g

    一.安装依赖包 yum -y install gcc make binutils gcc-c++ compat-libstdc++-33 elfutils-libelf-devel elfutils- ...

  7. 小程序展开收缩文字demo

    demo效果图: wxml 代码: <view class="{{ellipsis?'ellipsis':'unellipsis'}}">五险一金五五险一金险险一金五五 ...

  8. Java作业四(2017-10-8)

    import java.util.Scanner; public class Helloworld { public static void main(String[] args) { System. ...

  9. 反射RelectionDemo

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...

  10. 外网访问VMware虚拟机

      目的: 主机上安装了VMware,VMware上安装了Linux虚拟机(我安装的是Centos7).我想让虚拟机向外提供Web服务.本文记录如何让我的主机和外网用户可以访问VM虚拟机上的Web. ...