1. 程式人生 > >tarjan,樹剖,倍增求lca

tarjan,樹剖,倍增求lca

next 訪問 find int ext for pac using ins

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