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. IPVS和Nginx两种WRR负载均衡算法详解

    动机 五一临近,四月也接近尾声,五一节乃小长假的最后一天.今天是最后一天工作日,竟然感冒了,半夜里翻来覆去无法安睡,加上窗外大飞机屋里小飞机(也就是蚊子)的骚扰,实在是必须起来做点有意义的事了!    ...

  2. spring中@PropertySource注解的使用

    概述: The @PropertySource annotation provides a convenient and declarative mechanism for adding aPrope ...

  3. missing blocks错误

    Datanode的日志中看到: 10/12/14 20:10:31 INFO hdfs.DFSClient: Could not obtain block blk_XXXXXXXXXXXXXXXXXX ...

  4. vue双向绑定原理

    要了解vue的双向绑定原理,首先得了解Object.defineProperty()方法,因为访问器属性是对象中的一种特殊属性,它不能直接在对象中设置,而必须通过 Object.definePrope ...

  5. iOS 后台运行执行代码(例如定位)

  6. ViewPager使用--文章集锦

    viewpager中彻底性动态添加.删除Fragment Android ViewPager使用详解 fragment中嵌套viewpager,vierpager中有多个fragment,不显示 .. ...

  7. COGS2090 Asm.Def找燃料

    时间限制:1 s   内存限制:256 MB [题目描述] “听说咱们要完了?”比利·海灵顿拨弄着操纵杆,头也不回地问Asm.Def. “不要听得风就是雨.” “开个玩笑嘛.不就是打机器人,紧张啥,你 ...

  8. codefoeces problem 671D——贪心+启发式合并+平衡树

    D. Roads in Yusland Mayor of Yusland just won the lottery and decided to spent money on something go ...

  9. #error#错误原因:Cannot find executable for CFBundle 0x8ad60b0 (not loaded)

    #error#错误原因:Cannot find executable for CFBundle 0x8ad60b0 </Applications/Xcode.app/Contents/Devel ...

  10. linux下面which whereis find locate的使用

    我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索.这些是从网上找到的资料,因为有时很长时间不会用到,当要用的时候经常弄混了,所以放到这里方便使用. which    ...