LCA 补充

news/2024/11/14 13:31:35/文章来源:https://www.cnblogs.com/ppllxx-9G/p/18299462

LCA

之前学废了,回来补。

倍增版

首先是最常见的倍增版子,思路好理解,按倍增记录 \(father\),然后同时往上跳。

注意最后跳到的是那个 \(x \ne y\) 的,也就是 \(lca\) 的儿子,所以最后要返回父亲。

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+5;
int n,m,rt;
int head[N],tot;
struct E{int u,v;} e[N<<1];
void add(int u,int v) {e[++tot]={head[u],v}; head[u]=tot;}
int dep[N],fa[30][N];
void dfs(int u)
{for(int i=1;i<=25;i++)fa[i][u]=fa[i-1][fa[i-1][u]];for(int i=head[u];i;i=e[i].u){int v=e[i].v;if(dep[v]) continue;dep[v]=dep[u]+1; fa[0][v]=u;dfs(v);}
}
int lca(int x,int y)
{if(dep[x]<dep[y]) swap(x,y);for(int i=25;i>=0;i--) if(dep[fa[i][x]]>=dep[y]) x=fa[i][x];if(x==y) return x;for(int i=25;i>=0;i--) if(fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y];return fa[0][x];
}
int main()
{scanf("%d%d%d",&n,&m,&rt);for(int i=2;i<=n;i++){int x,y; scanf("%d%d",&x,&y);add(x,y); add(y,x);}dfs(dep[rt]=1);//!!!while(m--){int x,y; scanf("%d%d",&x,&y);printf("%d\n",lca(x,y));}return 0;
}

DFS 序版

原博客

我们记录每个点的 \(dfn\) 时间戳和 dfs 序。

应用的性质是 \(lca\) 的 dfs 序不会出现在 \(u\)\(v\) 之间出现。并且是在它们之前出现。

其中 dfs 序体现在 dfs 遍历时维护的 \(st\),也就是记录父亲。

最终 \(st[i][u]\) 表示的是以 \(u\) 的时间戳为起点,在dfs序上向后延长 \(2^i\) 位的深度最小值的节点的父亲,也就是 \(dfn\) 最小节点。

这里很神奇的是查询能直接查到 \(lca\),因为我们查询的是 \([dfn_u,dfn_v]\) 这段 \(dfs\) 序上的父亲时间戳最小值显然这个点一定就是 \(lca\)

(挂张图)

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+5;
int n,m,rt,dfn[N],num,st[20][N];
int head[N],tot;
struct E{int u,v;} e[N<<1];
void add(int u,int v) {e[++tot]={head[u],v}; head[u]=tot;}
int get(int x,int y) {return dfn[x]<dfn[y]?x:y;}
void dfs(int u,int fa)
{dfn[u]=++num; st[0][num]=fa;for(int i=head[u];i;i=e[i].u){int v=e[i].v;if(v!=fa) dfs(v,u);}
}
int lca(int x,int y)
{if(x==y) return x;x=dfn[x]; y=dfn[y];if(x>y) swap(x,y);int d=__lg(y-x);return get(st[d][x+1],st[d][y-(1<<d)+1]);
}
int main()
{scanf("%d%d%d",&n,&m,&rt);for(int i=2;i<=n;i++){int x,y; scanf("%d%d",&x,&y);add(x,y); add(y,x);}dfs(rt,0);for(int i=1;i<=__lg(n);i++)for(int j=1;j+(1<<i)-1<=n;j++)st[i][j]=get(st[i-1][j],st[i-1][j+(1<<i-1)]);while(m--){int x,y; scanf("%d%d",&x,&y);printf("%d\n",lca(x,y));}return 0;
}

树链剖分版

划分轻重链后往上跳,直到跳到同一条链上,其实就是借助了树剖的 dfs,亲民。

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+5;
int n,m,rt;
int head[N],tot;
struct E{int u,v;} e[N<<1];
void add(int u,int v) {e[++tot]={head[u],v}; head[u]=tot;}int sz[N],dep[N],fa[N],son[N],top[N];void dfs1(int u,int f)
{fa[u]=f; dep[u]=dep[f]+1; sz[u]=1; son[u]=-1;for(int i=head[u];i;i=e[i].u){int v=e[i].v;if(v==f) continue;dfs1(v,u);sz[u]+=sz[v];if(son[u]==-1||sz[son[u]]<sz[v]) son[u]=v;}
}
void dfs2(int u,int t)
{top[u]=t;if(son[u]==-1) return ;dfs2(son[u],t);for(int i=head[u];i;i=e[i].u){int v=e[i].v;if(v!=fa[u]&&v!=son[u]) dfs2(v,v);}
}
int lca(int x,int y)
{while(top[x]!=top[y]){if(dep[top[x]]>=dep[top[y]]) x=fa[top[x]];else y=fa[top[y]];}return dep[x]<dep[y]?x:y;
}
int main()
{scanf("%d%d%d",&n,&m,&rt);for(int i=2;i<=n;i++){int x,y; scanf("%d%d",&x,&y);add(x,y); add(y,x);}dfs1(rt,0); dfs2(rt,rt);while(m--){int x,y; scanf("%d%d",&x,&y);printf("%d\n",lca(x,y));}return 0;
}

写在最后

虽然原博列举了很多 dfs 序 LCA 的优点,但是缺点也有一点点吧。

倍增方法可以处理 k 级祖先,这在一些树上跳的题目中很重要。

树剖可以顺便求出 lca,用途也比较广。

dfs 序码量较短,但是不太好想。而且用途比较单一。

而且好像除了 dfs 序版以外都很好理解???

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/742932.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

读人工智能全传11人工智能会出什么错

读人工智能全传11人工智能会出什么错1. 人工智能会出什么错 1.1. 一些报道是公正合理的,不过坦白地说,大部分报道都愚蠢得无可救药 1.2. 一些报道颇有知识性和引导性,而大部分则是杞人忧天式的恐吓 1.3. 滑稽的报道迎合了大众对人工智能的“终结者式恐惧” 1.3.1. 我们创造出…

dotnet 理解 X11 的 24 位或 32 位色深窗口

本文记录在 X11 里面的窗口与颜色的位色深关系本文属于学习 CPF 框架博客,感谢小红帽的 CPF 框架。更多关于 CPF 框架,请参阅 https://gitee.com/csharpui/CPF 本文这里的 24 色或 32 色表示的是用多少个 bit 表示一个像素的颜色。比如常见的 24 色就是 RGB 三个颜色分量,一…

【C++】const与constexpr

const 用于声明该变量是一个常量。 可以用来声明成员函数,表示该函数不会改变成员变量。 const修饰指针的场景稍微复杂点,可以通过循环的方式记忆:constexpr constexpr 它是在 C++ 11 被引进的,它的字面意思是 constant expression,常量表达式。它可以作用在变量和函数上。…

ubuntu搭建docker harbor实录

一、搭建前提 一台2C2G ubuntu 18.04.6版本主机 配置好网络、ntp,关闭ufw二、搭建步骤 1、安装docker engine、docker-compose等 设置 Docker 的存储库# Add Dockers official GPG key: sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 …

【攻防技术系列+漏洞复现】Fastjson①前置知识 -- fastjson怎么用?

主题任务 在IDEA中新建一个maven项目,并引入fastjson依赖工具 IntelliJ IDEA 2020.3 JDK 11一、前置知识 1.1 fastjson怎么用? fastjson是啥百度就有,看了之后不熟悉的人还是会一脸懵逼,我们可以通过以下这个demo来快速学会使用fastjson。 我们分为以下几个步骤来进行: (…

24暑期第七次训练C组

目录ABCDEFGHIJ A 生活大爆炸版石头剪刀布 纯模拟,保证AB之间能对应就行。 给出较朴素做法。 bool caiquan(int,int);int main(void) {int n,x,y,ans1 = 0,ans2 = 0,stp;cin >> n >> x >> y;vector<int> a(x);vector<int> b(y);for(auto &i…

4-电子商务物理与供应链管理

4.1 电子商务与物流 4.1.1 物流及物流标准化 1.物流的概念 根据我国国家标准在GB/T18345—2006《物流术语》中的表述,物流(Logistics):“物品从供应地向接受地的实体流动过程。根据实际需要,将运输、储存、配送、包装、装卸搬运、流通加工、信息管理等基本功能实施有机结合…

比赛获奖的武林秘籍:06 5分钟速通比赛路演答辩,国奖选手的血泪经验!

本文主要介绍了大学生电子计算机类比赛和创新创业类比赛常见雷点、要点和精髓,并对路演的定义和基本概念进行了说明,结合自身经历对路演答辩常见技巧和评委问题进行了总结。比赛获奖的武林秘籍:06 5 分钟速通比赛路演答辩,国奖选手的血泪经验! 摘要 本文主要介绍了大学生电…

汽车虚拟仿真vr技术的三个关键方面!

汽车作为人类生活中不可或缺的交通工具,同时也是展示个性和品味的重要象征。随着科技的迅猛发展和消费者需求的不断升级,汽车行业正处于持续创新和变革之中,在这个过程中汽车虚拟仿真VR看车技术正扮演着至关重要的角色,接下来,我们将逐一深入探讨汽车虚拟仿真VR技术的三个…

点评一下新手画的电路图

目的 实现5v升压到12v 原理图pcb问题 这是一个简单的直接抄的LT1930的电路,想知道能够如何改进,还有我想做一个防止这玩意gnd和12v插反导致板子直接寄,如何处理,之后会自己学会如何真正看懂这个图,目前大一刚结束还没学习数模电。

通达OA,远程命令执行漏洞复现

一、漏洞描述 通达OA是由北京通达信科科技有限公司开发的一款办公系统,前一段时间通达官方在其官网发布了安全提醒与更新程序,并披露有用户遭到攻击。攻击者可在未授权的情况下可上传图片木马文件,之后通过精心构造的请求进行文件包含,实现远程命令执行,且攻击者无须登陆认…

通达OA,远程命令执行漏洞的 利用复现(Exp-tools,getshell)

一、漏洞描述 通达OA是由北京通达信科科技有限公司开发的一款办公系统,前一段时间通达官方在其官网发布了安全提醒与更新程序,并披露有用户遭到攻击。攻击者可在未授权的情况下可上传图片木马文件,之后通过精心构造的请求进行文件包含,实现远程命令执行,且攻击者无须登陆认…