首页 > 其他分享 >欧拉序求LCA

欧拉序求LCA

时间:2023-11-01 22:11:38浏览次数:27  
标签:int 序求 dfs st dfn LCA 欧拉

使用欧拉序 st 表 O(1) 求 LCA

 

欧拉序 st 表求 LCA

一开始是从某篇题解里看到的,后来百度了一下就会了(

这是一种预处理 O(nlogn) ,查询 O(1) 的优秀算法。

什么是欧拉序

举个例子,下面是一棵树:

上面有 dfs 与回溯的过程。

将整个 dfs 与回溯过程写出来:

1  →  2  →  4  →  7  →  4  →  8  →  4  →  2  →  5  →  2  →  1  →  3  →  6  →  3  →  1 

这就是欧拉序了。

如何求出答案

如何求 LCA 呢?

假设我们要求 LCA(3,7) 。

那我们先把欧拉序中 3,7 第一次出现的位置 标出来。

1  →  2  →  4  →  7  →  4  →  8  →  4  →  2  →  5  →  2  →  1  →  3  →  6  →  3  →  1 

LCA(3,7) 就是欧拉序标红的 3,73,7 之间深度最小的点,就是 11 。

暴力找一遍 3,73,7 之间深度最小的点肯定不行。

由于欧拉序不变,此时可以用 \text{st}st 表的方法优化,就能 O(1)O(1) 查询。

设 f[i][j] 表示欧拉序中第 ii 个点以及后面共 2^j 个点中深度最小的点。

dfs 预处理出欧拉序:

#define N 1000007
int n,m,rt;
struct edge{
    int to,nxt;
}e[N<<1];
int tot,head[N];
inline void adde(int u,int v){
    e[++tot]=(edge){v,head[u]};
    head[u]=tot;
}

int dep[N],lg[N<<1],f[N<<1][21];
int dfn[N<<1],que[N<<1],idx;
void dfs(int u,int pa)
{
    dfn[u]=++idx,que[idx]=u;
    dep[u]=dep[pa]+1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==pa)continue;
        dfs(v,u);
        que[++idx]=u;
    }
}

 

建 st 表:

void buildst()
{
    For(i,1,idx)f[i][0]=que[i];
    For(j,1,20)
        for(int i=1;i+(1<<j)<=idx;++i){
            int f1=f[i][j-1],f2=f[i+(1<<j-1)][j-1];
            f[i][j]=dep[f1]<dep[f2]?f1:f2;
        }
    lg[0]=-1;
    For(i,1,idx)lg[i]=lg[i>>1]+1;
}

 

查询:

inline int getlca(int u,int v)
{
    if(dfn[u]>dfn[v])swap(u,v);
    u=dfn[u],v=dfn[v];
    int kk=lg[v-u+1],f1=f[u][kk],f2=f[v-(1<<kk)+1][kk];
    return dep[f1]<dep[f2]?f1:f2;
}

 

看了一下 P3379 提交记录,发现 O(logn) 的树剖跑的比这个 O(1) 还快

update :

在 某题 里把树剖 LCA 换成了 st 表求 LCA 结果快了不少。

看来 st 表求 LCA 可以在查询次数多的情况下 用来卡常

 

标签:int,序求,dfs,st,dfn,LCA,欧拉
From: https://www.cnblogs.com/wenyutao1/p/17804247.html

相关文章

  • 欧拉函数 & 欧拉定理
    欧拉函数互质:对于\(\foralla,b\in\mathbb{N}\),若\(a,b\)的最大公因数为\(1\),则称\(a,b\)互质。欧拉函数:即$\varphi(N)$,表示从\(1\)到\(N\)中与\(N\)互质的数的个数。在算术基本定理中,任何一个大于\(1\)的整数都可以唯一分解为有限个质数的乘积,......
  • 学习笔记:欧拉图 & 欧拉路
    欧拉图&欧拉路定义图中经过所有边恰好一次的路径叫欧拉路径(也就是一笔画)。如果此路径的起点和终点相同,则称其为一条欧拉回路。欧拉回路:通过图中每条边恰好一次的回路。欧拉通路:通过图中每条边恰好一次的通路。欧拉图:具有欧拉回路的图。半欧拉图:具有欧拉通路但不具有欧拉......
  • 归并排序求逆序对
    #include<iostream>#include<algorithm>#include<cstring>usingnamespacestd;constintN=1e5+10;inta[N];intans=0;inttmp[N];voidmergesort(inta[],intl,intr){if(l>=r)return;intmid=l+r>>1;m......
  • (华为欧拉操作系统)openEuler 22.03 LTS SP2 安装使用记录
    本来是准备在虚拟机中安装rockylinux,,结果安装失败,你可以从第4步开始看。1.到 https://www.virtualbox.org/ 下载VirtualBox-7.0.12-159484-Win.exe  并安装 2.到 https://rockylinux.org/zh_CN/download/下载   Rocky-9.2-x86_64-dvd.iso 由于这个iso有8.8G,正......
  • 基于dfn序的O(nlogn)-O(1) lca
    \(dfn\)序的长度是欧拉序的一半,常数较小,并且代码便于理解背诵。让欧拉序求lca成为时代的眼泪。代码部分实现思路来自cqbz_dongjie点击查看代码autominlca=[&](intx,inty){return(dfn[x]<dfn[y])?x:y;};intt=std::__lg(n)+1;std::vector<std::vect......
  • LCA学习笔记
    定义最近公共祖先简称LCA(LowestCommonAncestor)。两个节点的最近公共祖先,就是这两个点的公共祖先里面,离根最远的那个。求法有多种求法,目前就学习了倍增和dfs序求LCA,等后面学新的了再加上。前置知识:ST表,dfs序。为方便说明,下面全都是求\(x\),\(y\)的LCA,设其为\(z......
  • LCA性质
    https://zhuanlan.zhihu.com/p/6443257001\[LCA(p_1,p_2,p_3...p_n)=LCA(LCA(LCA(p_1,p_2),p_3),...p_n)\]证明略2\[LCA(p_1,p_1,p_2)=LCA(p_1,p_2)\]所以LCA相关可以用ST表维护。......
  • 欧拉回路
    对于无向图:欧拉路的起点和终点的度数为奇数,其余点的度数为偶数。若起点和终点的度数也都为偶数,则为欧拉回路。对于有向图:欧拉路的起点出度比入度大\(1\),终点的入度比出度大\(1\),其余点出度和入度相等。若起点和终点入度、出度相等,则为欧拉回路。dfs求欧拉路每次递归......
  • P1967 [NOIP2013 提高组] 货车运输 (生成树,LCA)
    P1967[NOIP2013提高组]货车运输https://www.luogu.com.cn/problem/P1967首先有些边是没用的(比较小的边),比如两个点之间的两条(并行的)路,只有较大的会被走到,小的不会被走,因此可以直接去除小的边,即求最大生成树。接着做求任意两点经过的边的最小值就演变成求树上任意两点的最小树......
  • 6577: 暗的连锁 LCA+树上差分
    描述  Dark是一张无向图,图中有N个节点和两类边,一类边被称为主要边,而另一类被称为附加边。Dark有N–1条主要边,并且Dark的任意两个节点之间都存在一条只由主要边构成的路径。另外,Dark还有M条附加边。你的任务是把Dark斩为不连通的两部分。一开始Dark的附加边......