最近公共祖先学习小结1——在线倍增
2016-07-10 11:13
316 查看
学习时看网上资料空讲,难以理解,还是自己动手画一画,才好理解。这里记录下来,以防自己过久了忘记。
最近公共祖先(Lowest Common Ancestors)(简称LCA),简单讲就是指在树上几个节点共有的祖先节点中,最近的那一个。
例如:3祖先(父亲)节点是2,1、4的祖先(父亲)节点是6,2,1,那么2,1就是这两个点的公共祖先节点,而2离这两个最近,所以2是他们的LCA。
那么怎么求这东西呢?
最简单的就是沿着这个点的父亲往上搜,记录下所有的祖先,然后同样做另外一个点,直到找到第一个相同的祖先。
不难发现这种方法其实很慢,而且可以进行优化,优化的方法很多。
这个优化对后来的倍增有帮助:就是我们不用只搜一个点,而是两个点同时搜。
先将深度更深的那个往上移动,直到两个点为同一层后,再两个点同时往上跳,这样可以快很多。
倍增:这是求LCA的快捷方法之一,而且是在线算法,时间复杂度为nlogn(预处理)+logn(查询一次),是挺快的,只是略慢于离线Tarjan算法,但在线是其一大方面优势。
从上面的优化中,我们可以发现,每次向上跳一个太慢了,我们可以尝试让其跳多个。
设up[x][i]表示x节点的第2^i个祖先是谁,自然有up[x][0]=dad[x];
学过RMQ的知道,up[x][i]=up[up[x][i-1]][i-1],也就是x节点的第2^i个祖先就是x节点第2*(i-1)个祖先的第2^(i-1)个祖先(这话有些绕口,自己画画图)。
至于这个i最大是多少,我们取log2n向上取整,需要提前算出来。
首先我们就先预处理这个up数组:
接下来就是求祖先了,和上面一样,只是不再一个个跳,而是采用倍增思想,一次跳几个,但注意的是不可以跳过公共祖先哦!
当然,一个LCA不够,还要去掌握离线tarjan。
切入正题
先了解个概念:最近公共祖先(Lowest Common Ancestors)(简称LCA),简单讲就是指在树上几个节点共有的祖先节点中,最近的那一个。
例如:3祖先(父亲)节点是2,1、4的祖先(父亲)节点是6,2,1,那么2,1就是这两个点的公共祖先节点,而2离这两个最近,所以2是他们的LCA。
那么怎么求这东西呢?
最简单的就是沿着这个点的父亲往上搜,记录下所有的祖先,然后同样做另外一个点,直到找到第一个相同的祖先。
不难发现这种方法其实很慢,而且可以进行优化,优化的方法很多。
这个优化对后来的倍增有帮助:就是我们不用只搜一个点,而是两个点同时搜。
先将深度更深的那个往上移动,直到两个点为同一层后,再两个点同时往上跳,这样可以快很多。
倍增:这是求LCA的快捷方法之一,而且是在线算法,时间复杂度为nlogn(预处理)+logn(查询一次),是挺快的,只是略慢于离线Tarjan算法,但在线是其一大方面优势。
从上面的优化中,我们可以发现,每次向上跳一个太慢了,我们可以尝试让其跳多个。
设up[x][i]表示x节点的第2^i个祖先是谁,自然有up[x][0]=dad[x];
学过RMQ的知道,up[x][i]=up[up[x][i-1]][i-1],也就是x节点的第2^i个祖先就是x节点第2*(i-1)个祖先的第2^(i-1)个祖先(这话有些绕口,自己画画图)。
至于这个i最大是多少,我们取log2n向上取整,需要提前算出来。
首先我们就先预处理这个up数组:
void dfs(int x) { up[x][0]=dad[x]; fo(i,1,M) up[x][i]=up[up[x][i-1]][i-1]; fo(i,1,f[x][0]) if (f[x][i]!=dad[x]) { int u=f[x][i]; dad[u]=x; deep[u]=deep[x]+1; dfs(u); } }
接下来就是求祖先了,和上面一样,只是不再一个个跳,而是采用倍增思想,一次跳几个,但注意的是不可以跳过公共祖先哦!
if (deep[x]<deep[y]) swap(x,y);//其实换不换都无所谓了。 down(i,M,0) if (deep[y]<=deep[up[x][i]]) x=up[x][i];//先把深度深的弄到同一层用倍增思想。 if (x==y) return x;//如果y是x祖先,那么lca就是y了。 down(i,M,0) if (up[x][i]!=up[y][i]){//注意条件,不能跳过公共祖先。 x=up[x][i]; y=up[y][i]; } return up[x][0];//不能跳过公共祖先,只能跳到其的子节点,那么这个节点的父亲就是lca
当然,一个LCA不够,还要去掌握离线tarjan。
相关文章推荐
- 最近公共祖先(Tarjan算法)
- 并查集求最近公共祖先
- 最近公共祖先
- 【基础练习】【倍增LCA】codevs1036 商务旅行题解
- 【基础练习】【倍增LCA】codevs1503 愚蠢的宠物
- POJ 1330 Nearest Common Ancestors (在线LCA转RMQ)
- BZOJ 1602: [Usaco2008 Oct]牧场行走
- 【白话系列】最近公共祖先
- 【LCA最近公共祖先】HDU 2586 How far away ?
- Codevs P1036 商务旅行
- Codevs_P2370 小机房的树(LCA)
- Codevs_P1036 商务旅行(LCA)
- 算法基础 - 树的最近公共祖先
- 算法基础 - 最近公共祖先(在线算法/离线算法)
- 【算法】最近公共祖先之在线算法(RMQ-ST)
- 二叉搜索树(BST)的最近公共祖先(LCA)问题(Lowest Common Ancestor of a Binary Tree)
- 【LCA】最近公共祖先问题Lowest Common Ancestors
- Noip 2013 Day1 T3 货车运输 启发式并查集树
- BZOJ [Ahoi2008]Meet 紧急集合
- Range Minimum Query and Lowest Common Ancestor 区间最值查询和最近公共祖先问题