LCA的离线快速求法
最常见的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的离线快速求法的更多相关文章
- (私人收藏)[开发必备]最全JQuery离线快速查找手册(可查询可学习,带实例)
[开发必备]最全JQuery离线快速查找手册(可查询可学习,带实例) https://pan.baidu.com/s/16bUd4iA3p0c5RHbzaC60IQe4zh
- (私人收藏)[开发必备]最全Java离线快速查找手册(可查询可学习,带实例)
(私人收藏)[开发必备]最全Java离线快速查找手册(可查询可学习,带实例) https://pan.baidu.com/s/1L54VuFwCdKVnQGVc8vD1TQnwmj java手册 Ja ...
- 学习笔记--最近公共祖先(LCA)的几种求法
前言: 给定一个有根树,若节点\(z\)是两节点\(x,y\)所有公共祖先深度最大的那一个,则称\(z\)是\(x,y\)的最近公共祖先(\(Least Common Ancestors\)),简称\ ...
- poj 1986 Distance Queries(LCA:倍增/离线)
计算树上的路径长度.input要去查poj 1984. 任意建一棵树,利用树形结构,将问题转化为u,v,lca(u,v)三个点到根的距离.输出d[u]+d[v]-2*d[lca(u,v)]. 倍增求解 ...
- bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1272 Solved: 451[Submit][Status ...
- poj 1330 LCA (倍增+离线Tarjan)
/* 先来个倍增 */ #include<iostream> #include<cstring> #include<cstdio> #define maxn 100 ...
- hdu2586How far away ?(LCA LCATarjan离线)
题目链接:acm.hdu.edu.cn/showproblem.php?pid=2586 题目大意:有n个点,同n-1条带有权值的双向边相连,有m个询问,每个询问包含两个数x,y,求x与y的最短距离. ...
- POJ 1470 Closest Common Ancestors (LCA,离线Tarjan算法)
Closest Common Ancestors Time Limit: 2000MS Memory Limit: 10000K Total Submissions: 13372 Accept ...
- 最近公共祖先LCA Tarjan 离线算法
[简介] 解决LCA问题的Tarjan算法利用并查集在一次DFS(深度优先遍历)中完成所有询问.换句话说,要所有询问都读入后才开始计算,所以是一种离线的算法. [原理] 先来看这样一个性质:当两个节点 ...
随机推荐
- dfs:x+y=z
#include <iostream.h> int a[100]; static int stat=0; void dfs(int n) { if(n==3) { if(a[0]+a[1] ...
- 一文看懂:ChIP实验和qPCR定量分析怎么做|易基因技术
大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因. 染色质免疫共沉淀(Chromatin Immunoprecipitation,ChIP),是研究体内蛋白质与DNA相互作用的经典方法. ...
- 启动Tomcat,Idea控制台输出乱码 淇℃伅
解决:修改 tomcat 下的conf目录下 logging.properties这个文件ava.util.logging.ConsoleHandler.encoding修改为 为 GBK 就好了 ...
- Java中8种基本数据类型是哪些
1 public class Ceshi { 2 int a; 3 double b; 4 boolean c; 5 char d; 6 float f; 7 byte e; 8 long h; 9 ...
- Google Translate寻找之旅
须知 网站:https://translate.google.de/ TK对应入口函数:teanslate_m_zh_CN文件/vu函数 TKK对应文件:/index页面,直接搜索TKK值即可 Goo ...
- BGD(批量梯度下降)--学习笔记
函数凸凹性: 用到的范数知识: 详细解释:每一个元素的平方再开方.补充损失函数: Huber Loss知识点 loss函数可以通过loss参数进行设置.SGDRegressor支持以下的loss函数: ...
- (2)_引言Introduction【论文写作】
- putty 远程登录ubuntu的方法
首先,要确定linux的ssh服务已经开启了: 首先要确定开启了ssh-server: 安装:sudo apt-get install openssh-server 安装:su ...
- 重磅:前端 MVVM 与 FRP 的升阶实践 —— ReRest 可视化编程
ReRest (Reactive Resource State Transfer) 是前端开发领域新兴的方法论体系,它继承了 MVVM 与 FRP 编程理念,在技术上有不少创新.本文从专利稿修改而来, ...
- PAT A1001 A+B Format
Calculate a+b and output the sum in standard format -- that is, the digits must be separated into gr ...