tarjan,树剖,倍增求lca
Posted asdic
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tarjan,树剖,倍增求lca相关的知识,希望对你有一定的参考价值。
1.tarjan求lca
Tarjan(u)//marge和find为并查集合并函数和查找函数 { for each(u,v) //访问所有u子节点v { Tarjan(v); //继续往下遍历 marge(u,v); //合并v到u上 标记v被访问过; } for each(u,e) //访问所有和u有询问关系的e { 如果e被访问过; u,e的最近公共祖先为find(e); } }
2.倍增lca(在线)
#include<bits/stdc++.h> using namespace std; const int N=100000; const int M=1000000; int dep[N],fa[N][20]; int head[N],tot; struct node{int v,next;}e[N]; void insert(int u,int v){ e[++tot]=(node){v,head[u]};head[u]=tot;} void dfs(int u,int f){ dep[u]=dep[f]+1; fa[u]=f; for(int i=head[u];i;i=e[i].next){ int v=e[i].v; dfs(v,u);} } int lca(int x,int y){ int i,j; if(dep[x]<dep[y]) swap(x,y); for(i=0;(1<<i)<=dep[x];i++); --i; for(j=i;j>=0;j--) if(dep[x]-(1<<j)>=dep[y]) x=fa[x][j]; if(x==y) return x; for(j=i;j>=0;j--) if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j]; return fa[x][0];} int main(){ int n;cin>>n; for(int i=1;i<n;i++){ int u,v;cin>>u>>v; insert(u,v);insert(v,u);} dfs(1,0); for(int j=1;(1<<j)<=n;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; int q; cin>>q; while(q--){ int a,b;cin>>a>>b; cout<<lca(a,b)<<endl; }return 0; }
3.树剖lca(在线)
void dfs1(int u,int f){ dep[u]=dep[f]+1; siz[u]=1; fa[u]=f; for(int i=head[u];i;i=e[i].next){ int v=e[i].v; if(v==f) continue; dfs1(v,u); siz[u]+=siz[v]; if(siz[son[u]]<siz[v]) son[u]=v;}} void dfs2(int u,int tp){ top[u]=tp; // top就是当前所在链的顶端 if(!son[u]) return; dfs2(son[u],tp); for(int i=head[u];i;i=e[i].next){ int v=e[i].v; if(!top[v]) dfs2(v,v);}} int lca(int x,int y){ int fx=top[x],fy=top[y];//将x,y放到同一重链上 while(fx!=fy){ if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy); x=fa[fx],fx=top[x];} return dep[u]<dep[v]?u:v;}//选取深度小的输出
以上是关于tarjan,树剖,倍增求lca的主要内容,如果未能解决你的问题,请参考以下文章