最常见的LCA(树上公共祖先)都是在线算法,往往带了一个log。有一种办法是转化为“+-1最值问题”得到O(n)+O(1)的复杂度,但是原理复杂,常数大。今天介绍一种允许离线时接近线性求LCA的方法。

一个点和其他点的LCA必定是它到root路径上的所有节点之一,而另一个节点刚好在哪个节点下,LCA就是谁:

如图,标粗的箭头为当前搜索的路径,左边为已经搜索完毕的路径,右边的黑色节点尚未搜索。现在要求节点cur和节点a的LCA,显然a是什么颜色,LCA就也是这个颜色,如果a还没有被搜索到,那就不处理,把这个询问留给搜索到a的时候处理(那个时候cur肯定已经访问过了)。

那怎么做这个染色呢?我们对所有节点做一个并查集,每当一个节点搜索完毕,处理完了自己的答案,就把自己合并到父亲fa里面,那么在我搜完之后,父节点fa搜完之前,fa的其他所有儿子的公共祖先都是fa了:

当cur节点搜索完毕后,回到fa,讲cur修改为橙色并入到fa里(而且我们使用了并查集,此后查询cur的子节点也将得到fa),之后在fa搜索其他儿子节点时,他们和cur子树里的节点的LCA一定是fa,而当fa全部搜索完成后,他又被并入上级节点,以此类推,就可以在一遍dfs中就获取所有询问的答案。

参考代码:

int N, Q, p[MAX], qa[MAX], qb[MAX], ans[MAX];
vector<int> has[MAX]; struct ufs {
int in[MAX]; ufs() {
std::iota(in, in + N, 0);
}
void merge(int v, int u) { //! v合并给u
in[v] = u;
}
int find(int u) {
return in[u]==u ? u : (in[u] = find(in[u])); //! 带路径压缩
}
}; class Tree
{
std::vector<int> son[MAX];
ufs f; void getans(int u) {
for (auto v: son[u]) {
getans(v); f.merge(v, u); //! 处理子树后,将其并入
}
for (auto i: has[u]) {
auto v (qa[i]^qb[i]^u); //! 该询问的另一个点
if (f.find(v) != v) ans[i] = f.find(v);
}
} public:
#define root 0
Tree() {
for (int i = 1; i < N; ++i) son[p[i]].push_back(i);
getans(root);
}
#undef root
}; main() {
scanf("%d%d", &N, &Q);
for (int i = 1; i < N; ++i) scanf("%d", p + i);
for (int i = 0; i < Q; ++i) {
scanf("%d%d", qa + i, qb + i);
has[qa[i]].push_back(i);//! 把询问归到qa和qb下
has[qb[i]].push_back(i);
} auto tr = new Tree;
for (int i = 0; i < Q; ++i)
printf("%d\n", ans[i]);
}

一个提交地址:https://judge.yosupo.jp/problem/lca

LCA的离线快速求法的更多相关文章

  1. (私人收藏)[开发必备]最全JQuery离线快速查找手册(可查询可学习,带实例)

    [开发必备]最全JQuery离线快速查找手册(可查询可学习,带实例) https://pan.baidu.com/s/16bUd4iA3p0c5RHbzaC60IQe4zh

  2. (私人收藏)[开发必备]最全Java离线快速查找手册(可查询可学习,带实例)

    (私人收藏)[开发必备]最全Java离线快速查找手册(可查询可学习,带实例) https://pan.baidu.com/s/1L54VuFwCdKVnQGVc8vD1TQnwmj java手册 Ja ...

  3. 学习笔记--最近公共祖先(LCA)的几种求法

    前言: 给定一个有根树,若节点\(z\)是两节点\(x,y\)所有公共祖先深度最大的那一个,则称\(z\)是\(x,y\)的最近公共祖先(\(Least Common Ancestors\)),简称\ ...

  4. poj 1986 Distance Queries(LCA:倍增/离线)

    计算树上的路径长度.input要去查poj 1984. 任意建一棵树,利用树形结构,将问题转化为u,v,lca(u,v)三个点到根的距离.输出d[u]+d[v]-2*d[lca(u,v)]. 倍增求解 ...

  5. bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1272  Solved: 451[Submit][Status ...

  6. poj 1330 LCA (倍增+离线Tarjan)

    /* 先来个倍增 */ #include<iostream> #include<cstring> #include<cstdio> #define maxn 100 ...

  7. hdu2586How far away ?(LCA LCATarjan离线)

    题目链接:acm.hdu.edu.cn/showproblem.php?pid=2586 题目大意:有n个点,同n-1条带有权值的双向边相连,有m个询问,每个询问包含两个数x,y,求x与y的最短距离. ...

  8. POJ 1470 Closest Common Ancestors (LCA,离线Tarjan算法)

    Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 13372   Accept ...

  9. 最近公共祖先LCA Tarjan 离线算法

    [简介] 解决LCA问题的Tarjan算法利用并查集在一次DFS(深度优先遍历)中完成所有询问.换句话说,要所有询问都读入后才开始计算,所以是一种离线的算法. [原理] 先来看这样一个性质:当两个节点 ...

随机推荐

  1. 三面面试官:运行 npm run xxx 的时候发生了什么?

    事情是这样的,直接开讲 面试官:npm run xxx的时候,发生了什么?讲的越详细越好. 我(心想,简单啊): 首先,DNS 解析,将域名解析成 IP 地址,然后 TCP 连接,TCP 三次握手.. ...

  2. libpcap -学习1

    1.今天学到的最重要一点就是指定是否打开混杂模式(Promiscuous Mode),0表示非混杂模式,任何其他值表示混合模式.如果要打开混杂模式,那么网卡必须也要打开混杂模式,可以使用如下的命令打开 ...

  3. Dubbo 使用过程中都遇到了些什么问题?

    在注册中心找不到对应的服务,检查 service 实现类是否添加了@service 注解 无法连接到注册中心,检查配置文件中的对应的测试 ip 是否正确

  4. 使用 Spring Cloud 有什么优势?

    使用 Spring Boot 开发分布式微服务时,我们面临以下问题 与分布式系统相关的复杂性-这种开销包括网络问题,延迟开销,带宽问题,安全问题. 服务发现-服务发现工具管理群集中的流程和服务如何查找 ...

  5. String s = new String(“xyz”);创建了几个字符串对象?

    两个对象,一个是静态区的"xyz",一个是用 new 创建在堆上的对象.

  6. 基于redis实现未登录购物车

    springboot 工程 主要说明购物车流程(故将登录用户信息保存至session) 未登录时 将用户临时key 保存至cookie 有不足之处 请大佬指点 项目源码: https://github ...

  7. 数仓建模—OneID

    今天是我在上海租房的小区被封的第三天,由于我的大意,没有屯吃的,外卖今天完全点不到了,中午的时候我找到了一包快过期的肉松饼,才补充了1000焦耳的能量.但是中午去做核酸的时候,我感觉走路有点不稳,我看 ...

  8. 如何设置出IDEA中VCS下的Enable Version Control Intergration

    File–>settings–>Version Control

  9. C语言之基本语句分类(知识点5)

    一.C语言基本语句分类 ①数据定义语句 ②赋值语句 ③函数调用语句 ④表达式语句 ⑤流程控制语句 ⑥复合语句(多个大括号的层次) ⑦空语句 二.注意 ①scanf("%d,%d", ...

  10. ROS学习文章

    ros机器人到底有没有必要学习?