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 之间所有路径中深度最小的节 点,所 ...
随机推荐
- Application received signal SIGSEGV
Application received signal SIGSEGV (null) (( 0 CoreFoundation 0x0000000181037d50 <redacted> + ...
- Linux命令运行监测和软件安装
监测命令的运行时间 time command $ time sleep 5 real 0m5.003s # 程序开始至结束的时间,包括其它进程占用的时间片和IO时间 user 0m0.001s # 进 ...
- CAD利用Select2得到所有实体(网页版)
主要用到函数说明: IMxDrawSelectionSet::Select2 构造选择集.详细说明如下: 参数 说明 [in] MCAD_McSelect Mode 构造选择集方式 [in] VARI ...
- CAD设置背景图片
把图片作为背景图片可见但是不能编辑操作. 主要用到函数说明: _DMxDrawX::DrawImageToBackground 绘光栅图到背景.详细说明如下: 参数 说明 BSTR sFileName ...
- vue组件---插槽
(1)插槽内容 Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口. 在父级组件里可以 ...
- 使用cloudcompare进行对比轨迹及评价
0.预备知识: 我的系统是Ubuntu 16.04. 在其他发行版中,可能需要先安装snap(如有必要,请参阅相应的文档).快照发布在3个频道:“稳定”,“测试版”和“边缘”.“稳定版”和“测试版”频 ...
- Autowired和Resource的区别
Autowired是属于spring的注解,默认按类型装配,且依赖对象必须存在,如果允许为null,需要设置Autowired(required=false) Resource属于javax,默认 ...
- UVA - 1374 Power Calculus (dfs迭代加深搜索)
题目: 输入正整数n(1≤n≤1000),问最少需要几次乘除法可以从x得到xn ?在计算过程中x的指数应当总是正整数. 思路: dfs枚举次数深搜 注意: 1.指数如果小于0,就退出当前的搜索 2.n ...
- Java对象序列化为什么要使用SerialversionUID
1.首先谈谈为什么要序列化对象 把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通 ...
- CSC
CSC CSC Table of Contents 1. account 2. Contacts 3. <国家公派留学人员预订回国机票说明> 4. 回国手续 4.1. 申办及开具<留 ...