倍增法求LCA

倍增法求LCA

LCA(Least Common Ancestors)的意思是最近公共祖先,即在一棵树中,找出两节点最近的公共祖先。

倍增法是通过一个数组来实现直接找到一个节点的某个祖先,这样我们就可以在O(logn)的时间内求出求出任意节点的任意祖先。

然后先把两个节点中转化为深度相同的节点,然后一起向上递增,知道找到相同的节点,该节点就是这两个节点的最近公共祖先。

代码实现:

 1 #include<cstdio>
 2 #include<iostream>
 3 #define N 42000
 4 using namespace std;
 5 int next[N],to[N],head[N],num,deep[N],father[N][21],n,m,p,a,b,c;
 6 void add(int false_from,int false_to){
 7     next[++num]=head[false_from];
 8     to[num]=false_to;
 9     head[false_from]=num;
10 }
11 void dfs(int x){
12     deep[x]=deep[father[x][0]]+1;
13     for(int i=0;father[x][i];i++)
14         father[x][i+1]=father[father[x][i]][i];
15     for(int i=head[x];i;i=next[i])
16         if(!deep[to[i]]){
17             father[to[i]][0]=x;
18             dfs(to[i]);
19         }
20 }
21 int lca(int x,int y){
22     if(deep[x]>deep[y])
23         swap(x,y);
24     for(int i=20;i>=0;i--)
25         if(deep[father[y][i]]>=deep[x])
26             y=father[y][i];
27     if(x==y)
28         return y;
29     for(int i=20;i>=0;i--)
30         if(father[y][i]!=father[x][i]){
31             y=father[y][i];
32             x=father[x][i];
33         }
34     return father[x][0];
35 }
36 int main(){
37     scanf("%d%d%d",&n,&m,&p);
38     for(int i=1;i<n;++i){
39         scanf("%d%d",&a,&b);
40         add(a,b);
41         add(b,a);
42     }
43     dfs(p);
44     for(int i=1;i<=m;++i){
45         scanf("%d%d",&a,&b);
46         printf("%d ",lca(a,b));
47     }
48     return 0;
49 }

时间: 2024-10-05 13:48:14

倍增法求LCA的相关文章

poj1330Nearest Common Ancestors以及讲解倍增法求lca

Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20487   Accepted: 10784 Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: In the figure, each node is labeled with an

倍增法求lca:暗的连锁

https://loj.ac/problem/10131 #include<bits/stdc++.h> using namespace std; struct node{ int to,next; }e[1000001]; int head[500000],num=0,N,n,m,ans; int grand[500001][20],depth[500001]; int f[100000],w[1000000]; inline void add(int x,int y) { e[++num]

用“倍增法”求最近公共祖先(LCA)

1.最近公共祖先:对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大.2.朴素算法:记录下每个节点的父亲,使节点u,v一步一步地向上找父亲,直到找到相同的“祖先”,即 是所求的答案,时间复杂度O(n).3.优化算法(倍增法):利用二进制的思想,想办法使一步一步向上搜变成以2^k地向上跳. 所以定义一个P[][]数组,使p[i][j]表示节点i的2^j倍祖先,因此p[i][0]即为i的父亲. 我们可以得到一个递推式p[i][j]=p

SPOJ COT2 Count on a tree II (树上莫队,倍增算法求LCA)

题意:给一个树图,每个点的点权(比如颜色编号),m个询问,每个询问是一个区间[a,b],图中两点之间唯一路径上有多少个不同点权(即多少种颜色).n<40000,m<100000. 思路:无意中看到树上莫队,只是拿来练练,没有想到这题的难点不在于树上莫队,而是判断LCA是否在两点之间的路径上的问题.耗时1天. 树上莫队的搞法就是: (1)DFS一次,对树进行分块,分成sqrt(n)块,每个点属于一个块.并记录每个点的DFS序. (2)将m个询问区间用所属块号作为第一关键字,DFS序作为第二关键字

LCA 在线倍增法 求最近公共祖先

第一步:建树  这个就不说了 第二部:分为两步  分别是深度预处理和祖先DP预处理 DP预处理: int i,j; for(j=1;(1<<j)<n;j++) for(int i=0;i<n;++i) if(fa[i][j]=-1) fa[i][j]=fa[fa[i][j-1]][j-1];/*DP处理出i的2^j祖先是谁*/ 深度预处理: 1 void dfs(int now,int from,int deepth) 2 { 3 deep[now]=deepth; 4 for(i

Misha, Grisha and Underground CodeForces - 832D (倍增树上求LCA)

Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations connected with n - 1 routes so that each route connects two stations, and it is possible to reach every station from any other. The boys decided to h

HDU 5296 Annoying Problem 树链剖分 LCA 倍增法

HDU 5296 Annoying Problem 题目链接:hdu 5296 题意:在一棵给定的具有边权的树,一个节点的集合S(初始为空),给定Q个操作,每个操作增加或删除S中的一个点,每个操作之后输出使集合S中所有点联通的最小子树的边权和. 思路:最小子树上的节点的充要条件: 节点为(S集合中所有点的LCA)的子节点: 节点有一个子孙为S集合中的点. 那么我们给每个节点都开一个标记数组,初始为零,每加入一个节点,就把从这个节点到根节点路径上的点的值都+1,反之-1,这样通过对每个单节点值的查

POJ 1986:Distance Queries(倍增求LCA)

http://poj.org/problem?id=1986 题意:给出一棵n个点m条边的树,还有q个询问,求树上两点的距离. 思路:这次学了一下倍增算法求LCA.模板. dp[i][j]代表第i个点的第2^j个祖先是哪个点,dp[i][0] = i的第一个祖先 = fa[i].转移方程:dp[i][j] = dp[dp[i][j-1][j-1]. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm&g

求 LCA 的三种方法

(YYL: LCA 有三种求法, 你们都知道么?) (众神犇: 这哪里来的傻叉...) 1. 树上倍增 对于求 LCA, 最朴素的方法是"让两个点一起往上爬, 直到相遇", "如果一开始不在同一深度, 先爬到同一深度". 树上倍增求 LCA 的方法同样基于这个道理, 只不过利用了倍增思想从而加速了"向上爬"的操作. 也就是说, 每次向上爬的高度不是 1, 而是 2 的幂. 我们用 $f(i, j)$ 表示从节点 $i$ 向上爬 $2^j$ 的高度