博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【总结】LCA的4种求法
阅读量:5222 次
发布时间:2019-06-14

本文共 2179 字,大约阅读时间需要 7 分钟。

前言

LCA的求法有多重多样,总结下来是下面这4种.希望大家可以加油!

暴力求LCA

我们考虑dfs求出每一个点的父亲(在当前根下),然后直接先暴力跳到同一个深度,再同时跳

void dfs(int u,int f){    fa[u]=f;dep[u]=dep[f]+1;    for(re int i=front[u];i;i=e[i].nxt){        int v=e[i].to;        if(v==f)continue;        dfs(v,u);    }}int lca(int u,int v){    if(dep[u]

倍增求LCA

我们考虑每一次跳1个父亲的速度太慢,那么怎么优化呢?

这个时候就需要用到倍增这种思想了.

没有学过倍增的同学可以先写一下ST表,可能会对倍增有比较深刻的理解.

我们假设这样子一个变量\(f[i][j]\)表示点\(i\)的第\(2^j\)个父亲是哪个节点.

因为每一个数都可以二进制表示,所以我们考虑每一次从大到小枚举跳的东西,然后就可以做到\(\Theta(n\ log(n))\)

void dfs(int u,int fa){    dep[u]=dep[fa]+1;    for(re int i=front[u];i;i=nxt[i]){        int v=to[i];        if(v!=fa)dfs(v,u),f[0][v]=u;    }}int lca(int a,int b){    if(dep[a]
=dep[b]) a=f[i][a]; if(a==b)return a; for(re int i=20;~i;i--) if(f[i][a]!=f[i][b]) a=f[i][a],b=f[i][b]; return f[0][a];}

树链剖分求LCA

考虑把一个树分成轻链与重链,然后直接跳链就好了.

void dfs1(int u,int f){    fa[u]=f;siz[u]=1;dep[u]=dep[f]+1;    for(re int i=front[u];i;i=e[i].nxt){        int v=e[i].to;        if(v==fa[u])continue;        dfs1(v,u);        siz[u]+=siz[v];        if(siz[v]>siz[son[u]])son[u]=v;    }}void dfs2(int u,int tp){    top[u]=tp;    if(!son[u])return;    dfs2(son[u],tp);    for(re int i=front[u];i;i=e[i].nxt){        int v=e[i].to;        if(v==fa[u] || v==son[u])continue;        dfs2(v,v);    }}void swap(int &a,int &b){    int tmp=a;a=b;b=tmp;}int lca(int u,int v){    while(top[u]!=top[v]){        if(dep[top[u]]
dep[v]?v:u;}

Tarjan求LCA

考虑把每一个询问当做一条边处理,那么如果这两个都被访问了,显然另一个点的祖先一定是他们的LCA.

所以可以很容易地写出这一段代码.(注意最后合并)

int find(int x){    if(f[x]!=x)f[x]=find(f[x]);    return f[x];}void Add(int u,int v){    to[++cnt]=v;nxt[cnt]=front[u];    front[u]=cnt;}void Addques(int u,int v,int Id){    toq[++cnt]=v;    id[cnt]=Id;nxtq[cnt]=frontq[u];    frontq[u]=cnt;}void dfs(int u,int fa){    b[u]=1;    for(int i=front[u];i;i=nxt[i]){        int v=to[i];        if(v!=fa){            dfs(v,u);            for(int j=frontq[v];j;j=nxtq[j]){                int vv=toq[j];                if(b[vv])ans[id[j]]=find(vv);            }            int uu=find(u),vv=find(v);            if(uu!=vv)f[vv]=uu;        }    }}

转载于:https://www.cnblogs.com/cjgjh/p/9800148.html

你可能感兴趣的文章
03 线程池
查看>>
201771010125王瑜《面向对象程序设计(Java)》第十三周学习总结
查看>>
手机验证码执行流程
查看>>
python 基础 ----- 变量
查看>>
设计模式课程 设计模式精讲 2-2 UML类图讲解
查看>>
Silverlight 的菜单控件。(不是 Toolkit的)
查看>>
:hover 鼠标同时触发两个元素变化
查看>>
go语言学习十三 - 相等性
查看>>
Idea 提交代码到码云(提交到github也大同小异)
查看>>
c#连接excel2007未安装ISAM解决
查看>>
Mono 异步加载数据更新主线程
查看>>
初识lua
查看>>
我是插件狂人,jDuang,jValidator,jModal,jGallery
查看>>
张季跃 201771010139《面向对象程序设计(java)》第四周学习总结
查看>>
如何解除循环引用
查看>>
android中fragment的使用及与activity之间的通信
查看>>
字典【Tire 模板】
查看>>
jquery的contains方法
查看>>
python3--算法基础:二分查找/折半查找
查看>>
Perl IO:随机读写文件
查看>>