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

在深度遍历的任意时刻,我们将树中的节点分成三类:
1.我们已经访问了,但是我们还没有回溯的节点标记为1
2.我们访问过并且已经回溯到的,标记为2
3.没有访问过的节点
对于正在访问的节点x,他的父节点是标记为1的。若y是已经访问并且回溯的节点,则LCA(x, y)就是由y向上走,遇到的第一个标记为1的节点。
我们很容易想到可以使用并查集优化。
当一个节点标记为2时,我们把它合并到他父亲所在的集合(此时他的父亲一定标记为1且单独构成一个集合)
这就相当于每个完成回溯的几点都有一个指向它的父节点的指针,只需查询y所在集合的代表元素(并查集的get操作),就等价于从y向上一直走到一个开始递归但未回溯的节点,即LCA(x, y)
其实整个过程,自己在演草纸上画一遍就好了(建议换一篇博客看看)

 #include<bits/stdc++.h>
using namespace std;
const int maxn = ;
struct shiki {
int y, net;
}e[maxn << ];
struct enkidu {
int self, id, nex;
}ask[maxn << ];
int n, m, s;
int lin[maxn], len = ;
int both[maxn], tot = ;
int fa[maxn], lca[maxn];
int vis[maxn]; inline int read() {
int x = , y = ;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') y = -;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << ) + (x << ) + ch - '';
ch = getchar();
}
return x * y;
} inline void insert(int xx, int yy) {
e[++len].y = yy;
e[len].net = lin[xx];
lin[xx] = len;
} inline void add(int xx, int yy, int i) {
ask[++tot].self = yy;
ask[tot].id = i;
ask[tot].nex = both[xx];
both[xx] = tot;
} int getfather(int x) {
if(x == fa[x]) return x;
return fa[x] = getfather(fa[x]);
} void LCA_tarjan(int x) {
vis[x] = ;
for(int i = lin[x]; i; i = e[i].net) {
int to = e[i].y;
if(vis[to]) continue;
LCA_tarjan(to);
fa[to] = x;
}
for(int i = both[x]; i; i = ask[i].nex) {
int to = ask[i].self;
if(vis[to] == )
lca[ask[i].id] = getfather(to);
}
vis[x] = ;
} int main() {
memset(vis, , sizeof(vis));
n = read(), m = read(), s = read();
for(int i = ; i < n; ++i) {
int x, y;
x = read(), y = read();
insert(x, y);
insert(y, x);
}
for(int i = ; i <= n; ++i) fa[i] = i;
for(int i = ; i <= m; ++i) {
int x, y;
x = read(), y = read();
add(x, y, i);
add(y, x, i);
}
LCA_tarjan(s);
for(int i = ; i <= m; ++i)
cout << lca[i] << '\n';
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是一种稳定高速的算法 时间复杂度能做到预处理O(n + m ...

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

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

  5. 倍增 Tarjan 求LCA

                                                                                                         ...

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

  7. tarjan求lca的神奇

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

  8. Tarjan求LCA(离线)

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

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

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

随机推荐

  1. hdu6121 build a tree(树)

    题解: 可以考虑每一层结点的子树大小 必定满足下面的情况,即 a,a,a,a,a,a,b,c,c,c,c........ 然后每一层依次往上更新,结果是不变的 一共有logn层,所以依次扫上去,统计结 ...

  2. 机器学习模型-支持向量机(SVM)

    二.代码实现 import numpy as np from sklearn import datasets from sklearn.model_selection import train_tes ...

  3. 【POJ 2572 Advertisement】

    Time Limit: 1000MSMemory Limit: 10000K Total Submissions: 947Accepted: 345Special Judge Description ...

  4. BZOJ4008. [HNOI2015]亚瑟王 期望概率dp

    看到这道题想什么? 一个好转移的状态由于T最多444所以把每个点控制在O(400000)以内,所以对于n和r最多乘一次因此猜f[n][r],f[r][n],首先一轮一轮的搞不好转移,那么先想一想f[n ...

  5. 怎么给word加底纹

  6. HDU2553 N皇后问题---(dfs)

    http://acm.hdu.edu.cn/showproblem.php?pid=2553 在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在 ...

  7. python 读 excel 模块: xlrd

    主要来自:[ python中使用xlrd.xlwt操作excel表格详解 ] 为了方便阅读, 我将原文两个模块拆分为两篇博文: [ python 读 excel 模块: xlrd ] [ python ...

  8. [转载]超赞!32款扁平化Photoshop PSD UI工具包(下)

    32款扁平化风格的UI工具包第二弹!上篇为大家分享了16款风格各异的UI Kits,下篇继续为大家呈上16款精美的UI工具包,全部都有Photoshop PSD文件可以下载哦,喜欢就赶紧收藏吧! 17 ...

  9. JavaScript DOM编程艺术 读书笔记

    2. JavaScript语法 2.1 注释      HTML允许使用"<!--"注释跨越多个行,但JavaScript要求这种注释的每行都必须在开头加上"< ...

  10. Python学习笔记 - day2 - PyCharm的基本使用

    什么是IDE 开始学习的小白同学,一看到这三个字母应该是懵逼的,那么我们一点一点来说. 既然学习Python语言我们就需要写代码,那么代码写在哪里呢? 在记事本里写 在word文档里写 在sublim ...