倍增法求lca 模板

6 篇文章 0 订阅
struct tree
{
	int from,to,w;
	tree(int ff,int tt,int ww)
	{
		from=ff;to=tt;w=ww;
	}
	tree(){}
};
vector<tree>G;
vector<int>V[M*2];
int mxdeep;
int father[N][30];   //记录祖先结点编号 
int deep[N];        //记录结点深度
int dis[N][30];   //记录结点和祖先结点的距离 
void addtree(int from,int to,int w) //建边 
{
	G.push_back(tree(from,to,w));
	G.push_back(tree(to,from,w));
	int e=G.size();
	V[from].push_back(e-2);
	V[to].push_back(e-1);
} 
void init(int n)
{
	memset(father,0,sizeof(father));
	memset(deep,0,sizeof(deep));
	memset(dis,0,sizeof(dis));
	mxdeep=log(n*1.0)/log(2.0);
	G.clear();
	for(int i=0;i<=M;i++)
	V[i].clear();    
}
void dfs(int root) //根结点是输入时father[v][0]=0的点. 
{
	for(int i=1;i<=mxdeep;i++)
	{
		father[root][i]=father[father[root][i-1]][i-1];
		dis[root][i]=dis[father[root][i-1]][i-1]+dis[root][i-1];
		if(!father[root][i])   //优化,当为0的时候说明已经更新到了根结点位置 
		break;
	}
	for(int i=0;i<V[root].size();i++)
	{
		tree &e=G[V[root][i]];
		if(e.to!=father[root][0]) //说明e.to是root的儿子
		{
			deep[e.to]=deep[root]+1;
			father[e.to][0]=root;  //建立父子关系
			dis[e.to][0]=e.w;      //更新到父亲的距离
			dfs(e.to); 
		} 
	} 
}
int lca(int u,int v)
{
	int ans=0;
	if(deep[u]>deep[v])  //让u结点不在v结点下方,方便操作 
	swap(u,v);
	for(int i=mxdeep;i>=0;i--)  //将 v结点上移,但不能高于u结点 
	{
		if(deep[u]<deep[v]&&deep[u]<=deep[father[v][i]])
		{
			ans+=dis[v][i];
			v=father[v][i];
		}
	}
	if(v==u)
	return ans;
	for(int i=mxdeep;i>=0;i--)
	{
		if(father[v][i]!=father[u][i])  //一起移动到共同父亲处 
		{
			ans+=dis[v][i]+dis[u][i];
			v=father[v][i];
			u=father[u][i];
		}
	}
	if(v!=u) ans+=dis[v][0]+dis[u][0];  // 如果没有移动到同一处,可能是   1->u   1->v ,那么向上移动一个位置就可以了 
	return ans;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Tarjan算法是一种用于解决最近公共祖先(LCA)问题的离线算法。离线算法指的是在读取所有查询之后一次性计算所有查询的答案,而不是每读取一个查询就计算一次。\[1\] 在Tarjan算法中,需要使用并查集来实现。并查集是一种数据结构,用于维护元素之间的集合关系。下面是一个并查集的模板代码: ```cpp int fa\[100000\]; void reset(){ for (int i=1;i<=100000;i++){ fa\[i\]=i; } } int getfa(int x){ return fa\[x\]==x?x:getfa(fa\[x\]); } void merge(int x,int y){ fa\[getfa(y)\]=getfa(x); } ``` 在Tarjan算法的伪代码中,首先标记当前节点为已访问状态。然后遍历当前节点的子节点,递归调用Tarjan函数并合并子节点。接下来,遍历与当前节点有查询关系的节点,如果该节点已经访问过,则输出当前节点和该节点的LCA(通过并查集的查找函数getfa获取)。\[3\] 以上是关于Tarjan算法求解LCA的相关内容。 #### 引用[.reference_title] - *1* [Tarjan 算法解决 LCA 问题](https://blog.csdn.net/chengqiuming/article/details/126878817)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [详解使用 Tarjan 求 LCA 问题(图解)](https://blog.csdn.net/weixin_34315485/article/details/93801193)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值