博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[模板] 最近公共祖先/lca
阅读量:7142 次
发布时间:2019-06-29

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

简介

最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点.

定理.\(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * (r,fa(lca))\). (树上差分)

求法

tarjan

离线算法, 总时间 \(O(n+q)\). (q表示询问次数)

//利用前向星存储询问struct te{int t,pr,lca;}edge[1000050],qedge[1000050];int head[500050],pe=1,qhead[500050],pq=1;void adde(int f,int t){    edge[++pe].t=t;    edge[pe].pr=head[f];    head[f]=pe; }void addq(int f,int t){    qedge[++pq].t=t;    qedge[pq].pr=qhead[f];    qhead[f]=pq;}//并查集int fa[500050];int find(int p){return p==fa[p]?p:fa[p]=find(fa[p]);}void merge(int l,int r){fa[r]=l;}//merge r to l//tarjanint vi[500050];void tar(int p){    vi[p]=1;    for(int i=head[p];i;i=edge[i].pr){        if(vi[edge[i].t])continue;        tar(edge[i].t);        merge(p,edge[i].t);    }    for(int i=qhead[p];i;i=qedge[i].pr)        if(vi[qedge[i].t])            qedge[i].lca=qedge[i^1].lca=find(qedge[i].t);}

倍增

\(O(n\log n)\)预处理, \(O(\log n)\) 查询, \(O(n\log n)\)空间. 由于利用结合律, 可以维护一些链上信息. 可以动态维护.

int fa[nsz][20],dep[nsz]{-1};//动态维护void addfa(int p,int f){    dep[p]=dep[f]+1;    fa[p][0]=f;    rep(i,1,18)fa[p][i]=fa[fa[p][i-1]][i-1];}//静态void init(){    dfs(1,0); //get fa[i][0]    rep(i,1,18)rep(j,1,n)fa[j][i]=fa[fa[j][i-1]][i-1];}int lca(int a,int b){    if(dep[a]
=dep[b])a=fa[a][i]; if(a==b)return a; repdo(i,18,0)if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i]; return fa[a][0];}

欧拉序+rmq

\(O(n\log n)\)预处理, \(O(1)\) 查询, \(O(n\log n)\)空间.

int l2n[nsz*3+50];int eul[nsz*3],cnt=0,vis[nsz],d[nsz];int stt[nsz*3][21];void dfs(int u,int fa){    eul[++cnt]=u;    if(vis[u]==0)vis[u]=cnt,d[u]=d[fa]+1;    for(int i=hd[u],v=edge[i].t;i;i=edge[i].pr,v=edge[i].t){        if(v==fa)continue;        dfs(v,u);        eul[++cnt]=u;    }}int dmin(int a,int b){return d[a]<=d[b]?a:b;}void rmq(){    rep(i,1,cnt)stt[i][0]=eul[i];    rep(j,1,l2n[pe]){        rep(i,1,pe+1-(1<
y)swap(x,y); return stqu(x,y);}

树链剖分

\(O(n)\)预处理, \(O(\log n)\) 查询, \(O(n)\)空间. 由于利用结合律, 可以维护一些链上信息.

int dep[nsz],sz[nsz],son[nsz],fa[nsz],top[nsz];void dfs1(int p,int f){    sz[p]=1,dep[p]=dep[f]+1,fa[p]=f;    for(int i=hd[p],v=edge[i].t;i;i=edge[i].pr,v=edge[i].t){        if(v==f)continue;        dfs1(v,p);        sz[p]+=sz[v];        if(son[p]==0||sz[son[p]]
=dep[top[y]])x=fa[top[x]]; else y=fa[top[y]]; } return dep[x]

转载于:https://www.cnblogs.com/ubospica/p/10260434.html

你可能感兴趣的文章
vue-cli解析
查看>>
python进行毫秒级计时时遇到的一个精度问题
查看>>
tweak
查看>>
Innodb索引以及查询优化的一些见解
查看>>
SSM学习系列(三) Hello Spring MVC
查看>>
教你如何直接访问php实例对象的private属性
查看>>
sass的基本使用
查看>>
chrome扩展推荐:帮你留住每一次ctrl+c --- Clipboard History 2
查看>>
恶意软件盯上了加密货币,两家以色列公司受到攻击
查看>>
专访《Haskell函数式编程入门》作者张淞:浅谈Haskell的优点与启发
查看>>
VS2017 15.4提供预览版,面向Windows 10秋季更新(FCU)
查看>>
Spring Web Services 3.0.4.RELEASE和2.4.3.RELEASE发布
查看>>
如何自动搞定全站图片的alt属性?
查看>>
配置一次,到处运行:将配置与运行时解耦
查看>>
突发热点事件下微博高可用注册中心vintage的设计\u0026实践
查看>>
Elixir 1.3带来新的语言功能、API和改进后的工具
查看>>
用Elm语言降低失败的风险
查看>>
抓住热门话题一对一直播,如何在风浪四起的直播市场劈风斩浪? ...
查看>>
手把手教你用owncloud搭建属于自己的云盘
查看>>
epoll+socket实现 socket并发 linux服务器
查看>>