luogu3379 【模板】最近公共祖先(LCA) Tarjan
LCA的Tarjan算法是一个离线算法,复杂度$O(n+q)$。
我们知道Dfs搜索树时会形成一个搜索栈。搜索栈顶节点cur时,对于另外一个节点v,它们的LCA便是v到根节点的路径与搜索栈开始分叉的那个节点lca。而站在cur上枚举v找lca的过程可以用并查集优化到$O(\log n)$级别。
并查集的定义:规定v为已经搜索且已经回溯,当前搜索栈顶为cur,则v并查集中的Father为LCA(cur,v)。查询可直接运用该定义。
并查集的维护:每当搜索栈顶弹出一个节点x时,将x在并查集中的Father设为其在树中的Father。这样x及x的子树的Father就都是这个栈内节点x->Father了。
注意,不要用vector,全部用邻接表,否则慢。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int MAX_NODE = 500010, MAX_PATH = 500010; struct Node;
struct Edge;
struct Path;
struct Link; struct Node
{
int DfsN;
Edge *Head;
Node *UnFa;//UnionFather
Node *Father;
Link *HeadLink;
}_nodes[MAX_NODE], *Root;
int TotNode; struct Edge
{
Node *To;
Edge *Next;
}_edges[MAX_NODE * 2];
int _eCount; struct Path
{
Node *From, *To;
Node *Lca;
}_paths[MAX_PATH];
int TotPath; struct Link
{
Node *To;
Path *Query;
Link *Next;
}_links[MAX_PATH * 2];
int LinkCnt; void AddEdge(Node *from, Node *to)
{
Edge *e = _edges + ++_eCount;
e->To = to;
e->Next = from->Head;
from->Head = e;
} void AddLink(Node *from, Node *to, Path *query)
{
Link *cur = _links + ++LinkCnt;
cur->To = to;
cur->Query = query;
cur->Next = from->HeadLink;
from->HeadLink = cur;
} void InitAllPath()
{
for (int i = 1; i <= TotPath; i++)
{
AddLink(_paths[i].From, _paths[i].To, _paths + i);
AddLink(_paths[i].To, _paths[i].From, _paths + i);
}
} Node *GetRoot(Node *cur)
{
return cur->UnFa == cur ? cur : cur->UnFa = GetRoot(cur->UnFa);
} void Tarjan(Node *cur, Node *fa)
{
cur->DfsN = 1;
cur->UnFa = cur;
cur->Father = fa;
for (Edge *e = cur->Head; e; e = e->Next)
{
if (e->To == cur->Father)
continue;
Tarjan(e->To, cur);
e->To->UnFa = cur;
}
for (Link *link = cur->HeadLink; link; link = link->Next)
if (link->To->DfsN == 2)
link->Query->Lca = GetRoot(link->To);
cur->DfsN = 2;
} int main()
{
int rootId;
scanf("%d%d%d", &TotNode, &TotPath, &rootId);
Root = _nodes + rootId;
for (int i = 1; i <= TotNode - 1; i++)
{
int u, v;
scanf("%d%d", &u, &v);
AddEdge(_nodes + u, _nodes + v);
AddEdge(_nodes + v, _nodes + u);
}
for (int i = 1; i <= TotPath; i++)
{
int u, v;
scanf("%d%d", &u, &v);
_paths[i].From = _nodes + u;
_paths[i].To = _nodes + v;
}
InitAllPath();
Tarjan(Root, NULL);
for (int i = 1; i <= TotPath; i++)
printf("%lld\n", _paths[i].Lca - _nodes);
return 0;
}
luogu3379 【模板】最近公共祖先(LCA) Tarjan的更多相关文章
- [模板] 最近公共祖先/lca
简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...
- 最近公共祖先LCA(Tarjan算法)的思考和算法实现
LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现 小广告:METO CODE 安溪一中信息学在线评测系统(OJ) //由于这是第一篇博客..有点瑕疵...比如我把false写成了f ...
- 最近公共祖先 LCA Tarjan算法
来自:http://www.cnblogs.com/ylfdrib/archive/2010/11/03/1867901.html 对于一棵有根树,就会有父亲结点,祖先结点,当然最近公共祖先就是这两个 ...
- 最近公共祖先LCA Tarjan 离线算法
[简介] 解决LCA问题的Tarjan算法利用并查集在一次DFS(深度优先遍历)中完成所有询问.换句话说,要所有询问都读入后才开始计算,所以是一种离线的算法. [原理] 先来看这样一个性质:当两个节点 ...
- 最近公共祖先LCA(Tarjan算法)的思考和算法实现——转载自Vendetta Blogs
LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现 小广告:METO CODE 安溪一中信息学在线评测系统(OJ) //由于这是第一篇博客..有点瑕疵...比如我把false写成了f ...
- POJ 1986 Distance Queries (最近公共祖先,tarjan)
本题目输入格式同1984,这里的数据范围坑死我了!!!1984上的题目说边数m的范围40000,因为双向边,我开了80000+的大小,却RE.后来果断尝试下开了400000的大小,AC.题意:给出n个 ...
- Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)
Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...
- POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)
POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...
- POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)
POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...
- 【lhyaaa】最近公共祖先LCA——倍增!!!
高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...
随机推荐
- kvm--virsh命令行下管理虚拟机
virsh 既有命令行模式,也有交互模式,在命令行直接输入 virsh 就进入交互模式, virsh 后面跟命令参数,则是命令行模式: (1)基础操作 --- 命令行下管理虚拟机 virsh list ...
- cmd命令安装、卸载、启动和停止Windows Service
1.运行--〉cmd:打开cmd命令框 2.在命令行里定位到InstallUtil.exe所在的位置 InstallUtil.exe 默认的安装位置是在C:/Windows/Microsoft.NET ...
- 字符串系列——KMP模板整理
KMP模板整理 KMP与扩展KMP: /*vs 2017/ vs code以外编译器,去掉windows.h头文件和system("pause");*/ #include<i ...
- DH密钥交换算法
DH密钥交换算法:DH的全称为Diffie-Hellman ,该算法可以在需要安全传输的前提下,确定双方的对称密钥,该算法的核心在于双方的私钥没有进入网络传输流程,根据对方的公钥和己方的私钥,可以计算 ...
- 洛谷——P3919 【模板】可持久化数组(可持久化线段树/平衡树)
P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目背景 UPDATE : 最后一个点时间空间已经放大 标题即题意 有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集 ...
- Gym - 101550A(Artwork 倒序+并查集)
题目: 思路: 1.对输入数据离线,先把所有的黑线都画出来,统计一下剩余的白色连通块的个数,dfs过程将一个连通块放到一个集合中. 2.倒着往前消去黑线,如果当前的块A是白块就看他的四周有没有白块:有 ...
- Random和ArrayList的应用
/*Random类应用与Math类应用,创建一个类, * 1)分别用Random类和Math.random()方法生成随机数. * 2) 把Math.random()方法生成的随机数,转换成1-100 ...
- HDU 4780 Candy Factory
Candy Factory Time Limit: 2000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ...
- HDU 3308 (线段树区间合并)
http://acm.hdu.edu.cn/showproblem.php?pid=3308 题意: 两个操作 : 1 修改 单点 a 处的值. 2 求出 区间[a,b]内的最长上升子序列. 做法 ...
- 【故障处理】初始化数据时报600错误kcbz_check_objd_typ_3
http://blog.itpub.net/519536/viewspace-661905/