关于最近公共祖先之树链剖分

该方法结合了深度优先搜索的倍增思想和路径压缩技术,分为找重儿子、确定重链和搜索最近公共祖先三个步骤。首先通过深搜确定每个节点的重儿子和子树大小,然后进行路径压缩,最后通过调整节点位置找到最近公共祖先。此外,文章还提及了其他两种不同的解决策略。

思路:

此做法有点难,结合了我的 毕生所学,用了第一种思想的倍增和第二种思想的路径压缩。

此做法分为3个部分:

  1. 找每个结点的重儿子。
  2. 确定所有重链。
  3. 向上搜最近公共祖先。

f a fa fa 记录父结点, s o n son son 记录重儿子, t o p top top 记录每条重链的头, s z sz sz 记录子树的结点数, d e p dep dep 记录深度, v e c t o r < i n t > e i j vector<int>e_{ij} vector<int>eij 维护整棵树。

①利用深搜,从根开始,搜出 s z sz sz s o n son son s o n son son 是根据最大的儿子 s z sz sz 确定的。

②还是用深搜来使一条重链上的所有结点指向顶点(类似路径压缩),分三种情况:叶子结点、重儿子、轻儿子。

③设 u , v u,v u,v 为查找的两点, u u u 所在的重链始终在 v v v 下面,然后 u u u 跳到上面一条重链,当它们在同一条重链上时,返回深度较小的那个。

核心代码:

void dfs1(int u,int f){
  fa[u]=f;
  dep[u]=dep[f]+1;
  sz[u]=1;
  for(auto v:e[u]){
  	if(v!=fa[u]){
  		dfs1(v,u);
  		sz[u]+=sz[v];
  		if(sz[son[u]]<sz[v])son[u]=v;
  	}
  }
}
void dfs2(int u,int t){
  top[u]=t;
  if(!son[u])return;
  dfs2(son[u],t);
  for(auto v:e[u]){
  	if(v!=fa[u]&&v!=son[u])dfs2(v,v);
  }
}
int lca(int u,int v){
  while(top[u]!=top[v]){
  	if(dep[top[u]]<dep[top[v]])swap(u,v);
  	u=fa[top[u]];
  }
  return dep[u]<dep[v]? u:v;
}

另外两种也很不错的方法:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值