LCA学习心得

原创 2018年04月16日 22:55:18

嗯...今天只更新倍增版的 明天看写不写st表 树剖 tarjan等其他实现方式

1.写在前面

其实倍增版lca很好理解 代码看着也不恶心 但据说常数大 跑得慢(相比其他的几种方式)

2.细节一----关于邻接表的处理

无向图记得add两次就好了.....以及edge数组大小——边的两倍

    细节二----fa[now][i]=fa[fa[now][i-1]][i-1];

 这个比较重要由于不是二叉树 因此无法直接*2

fa[now][i-1]是now往上跳2^(i-1)的位置

由于2^i=2^(i-1)+2^(i-1) 因此再跳2^(i-1)就行了

(fa[now][i-1]之前必定处理过,fa[fa[now][i-1]][i-1]也是)

   然后应该没啥了..其他细节应该没什么了 看看我的注释就好了

#include<bits/stdc++.h>
using namespace std;
int n,m,s,tot; 
int first[500005],deepth[500005],fa[500005][25];
struct node
{
	int to;
	int next;
}edge[500005*2];
int read()
{
	int k=0;
	char ch=getchar();
	while(!isdigit(ch))	ch=getchar();
	while(isdigit(ch))	
	{
		k=k*10+ch-'0';
		ch=getchar();
	}
	return k;
}
inline void add(int x,int y)
{
	++tot;
	edge[tot].to=y;
	edge[tot].next=first[x];
	first[x]=tot;
}
void dfs(int now,int father)
{
	deepth[now]=deepth[father]+1;
	fa[now][0]=father;	//2的0次方是1 距离1当然就是自己的爸爸
	for(int i=1;(1<<i)<=deepth[now];i++)	//找now往上的fa数组 
	{
		fa[now][i]=fa[fa[now][i-1]][i-1];	//不是二叉树 因此无法直接*2	//fa[now][i-1]是now往上跳2^i-1的位置
		// 由于2^i=2^(i-1)+2^(i-1) 因此再跳2^(i-1)就行了 
	} 
	for(int i=first[now];i;i=edge[i].next)
	{
		int vis=edge[i].to;
		if(vis!=father)	dfs(vis,now);
	}
}
int lca(int x,int y)
{
	if(deepth[x]<deepth[y])	swap(x,y);	//保证x的深度总是大的那个 
	for(int i=21;i>=0;--i)
	{
		if(deepth[fa[x][i]]>=deepth[y])	x=fa[x][i];	//x往上跳 直到跳到一个点 使得这个点的深度=y的深度(y)(由于2^i相加可以到达任何点) 
	}
	if(x==y)	return x; 
	for(int i=21;i>=0;--i)
	{
		//两个节点最近公共祖先以上的根必定也是这两个点的祖先 
		if(fa[x][i]!=fa[y][i])
		{
			x=fa[x][i];
			y=fa[y][i];
		}
		//使x,y成为最浅的满足deepth[x]==deepth[y],且x!=y的两个点
		//此时的x,y 不管i为多少 fa[x][i]一定等于fa[y][i] 
	}
	return fa[x][0];
} 
int main()
{
//	freopen("wordin.in","r",stdin);
	n=read();
	m=read();
	s=read();
	for(int i=1;i<=n-1;i++)
	{
		int x,y;
		x=read();
		y=read();
		add(x,y);
		add(y,x);
	}
	dfs(s,0);	//默认起点的根为0
	for(int i=1;i<=m;i++)
	{
		int x,y;
		x=read();
		y=read();
		printf("%d\n",lca(x,y));
	}
	return 0; 
}

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Patrickpwq/article/details/79967873

人工智能工程师直通车第一期

-
  • 1970年01月01日 08:00

LCA 三种 解决方法讲解 (附加例题)

LCA(Least Common Ancestors)   即最近公共祖先,是指这样一个问题:在有根树中,找出某两个结点u和v最近的公共祖先(另一种说法,离树根最远的公共祖先)。 一、在线算法ST...
  • Cynthia_wjyi
  • Cynthia_wjyi
  • 2015-08-14 16:40:57
  • 2138

LCA在线算法ST算法

求LCA(最近公共祖先)的算法有好多,按在线和离线
  • y990041769
  • y990041769
  • 2014-11-07 08:47:49
  • 17976

树链剖分求LCA(最近公共祖先)

LCA(Lowest Common Ancestor 最近公共祖先)定义如下:在一棵树中两个节点的LCA为这两个节点所有的公共祖先中深度最大的节点。 如图,节点11与节点6的LCA为节点4,节点...
  • wazwaztime
  • wazwaztime
  • 2016-05-15 11:02:51
  • 3151

LCA实现的三种不同的方法

LCA,最近公共祖先,实现有多种不同的方法,在树上的问题中有着广泛的应用,比如说树上的最短路之类。 LCA的实现方法有很多,比如RMQ、树链剖分等。今天来讲其中实现较为简单的三种算法:RMQ+时间戳、...
  • WenDavidOI
  • WenDavidOI
  • 2016-02-15 19:37:38
  • 5785

各种LCA的模板

好久没有写博客了,联赛前一天来写一点关于LCA的各种模板 极力推荐第四种方法1.Sparce_Table 算法把树按照DFS序重新编号并求出DFS序列后,利用序列中两点编号之间的最小值即为LCA的性...
  • Sunshine_cfbsl
  • Sunshine_cfbsl
  • 2016-11-18 15:07:01
  • 428

浅谈LCA的离线算法

在线算法与离线算法的定义 在计算机科学中,一个在线算法是指它可以以序列化的方式一个个的处理输入,也就是说在开始时并不需要已经知道所有的输入。相对的,对于一个离线算法,在开始时就需要知道问题的所有输入...
  • u013076044
  • u013076044
  • 2014-12-11 21:23:51
  • 1259

LCA 转 RMQ算法 【总结】

首先,在你看这个算法之前,要确保你理解了RMQ的 ST 算法。 但是不理解没关系啊,提供通道:  点我 声明:这是方便我以后复习用的,所以总结不是特别详细。 LCA - 最近公共祖先:在有根树...
  • chenzhenyu123456
  • chenzhenyu123456
  • 2015-08-08 18:48:28
  • 1620

RMQ与LCA ACM必备

  • 2009年09月27日 14:40
  • 165KB
  • 下载

lca倍增算法学习记录

找最近公共父节点这问题很容易想到让两节点一起往上走最后相遇,但这样的dfs显然很慢,于是就需要倍增。就是用二进制的思维,以1,2,4,8等2的阶层步长接近答案,比一步一步向上要快很多。 所以要dfs...
  • wangwangbu
  • wangwangbu
  • 2016-05-19 13:25:09
  • 3034
收藏助手
不良信息举报
您举报文章:LCA学习心得
举报原因:
原因补充:

(最多只允许输入30个字)