「dfs 序求 lca」学习笔记

一种 O(nlogn) 预处理,O(1) 查询 lca 的算法,类似于压缩版的欧拉序求 lca 做法,但时空复杂度更优。

对于两点 x,y,不妨设 dfnx<dfny

  • x=ylca(x,y)=x,这个需要特判。
  • x,ylca 的两棵不同子树上,从 xy 的路径就是 xlcalcay,发现 lcay 这一条路径上除了 lca 其余节点 idfn 均满足 dfnxdfnidfny,故此直接求 dfni 在区间 [dfnx,dfny] 内的节点 idepi 最小的那个点,其父亲就是 lca(x,y)
  • yx 的子树上,lca(x,y)=x,其实可以特判,但不简洁,不妨取 x 满足 dfnx=dfnx+1,再按照上述过程处理,答案依旧正确。

最后发现使 dfnx=dfnx+1 的操作对于第二种情况对答案也没有影响,故此是一种通解。

上述操作可以用 ST 表维护。

该方法对于大多数题尤其询问时不允许多个 log 的情况下十分优秀,但由于树剖常数巨小,非特殊情况用树剖求 lca 也是一种不错的选择。

  • 附录:c++ 库内自带函数 __lg(n)O(1),而 log2(n) 复杂度为 log2n
void dfs(int x,int fa)
{
dfn[x]=++tot; mi[tot][0]=fa;
for(int y:e[x]) if(y!=fa) dfs(y,x);
}
int min_(int x,int y) {return dfn[x]<dfn[y]?x:y;}
void ST()
{
for(int j=1;j<=__lg(n);j++)
for(int i=1;i+(1<<j)-1<=n;i++)
mi[i][j]=min_(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
}
int lca(int x,int y)
{
if(x==y) return x;
x=dfn[x],y=dfn[y];
if(x>y) swap(x,y);
x++; int t=__lg(y-x+1);
return min_(mi[x][t],mi[y-(1<<t)+1][t]);
}
posted @   卡布叻_周深  阅读(41)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示