思路:
此做法有点难,结合了我的 毕生所学,用了第一种思想的倍增和第二种思想的路径压缩。
此做法分为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;
}
该方法结合了深度优先搜索的倍增思想和路径压缩技术,分为找重儿子、确定重链和搜索最近公共祖先三个步骤。首先通过深搜确定每个节点的重儿子和子树大小,然后进行路径压缩,最后通过调整节点位置找到最近公共祖先。此外,文章还提及了其他两种不同的解决策略。
9271

被折叠的 条评论
为什么被折叠?



