LCA【Tarjan】

首先,我们先来了解LCA。

LCA 是树上两个点最近的公共祖先。

比如说,在如图的树中,3与4的公共祖先有“2”,“1”,但最近的祖先是“2”。

显然,暴力可以做O(n),但是我们希望更快。

现在,有两种方法:

  1)在线操作,但这需要“倍增”,再此不讨论。

  2)离线操作,使用Tarjan与并查集。

先给出操作方法:

DFS (u)
   for i in u.son
      DFS(i)
      UNION(u,i)
   for i in u.e # e 表示 e 与访问所有和u有询问关系的i
      if i.vis
         (u,i).LCA = find(i)

可以发现,操作是在深搜中进行的。下面开始模拟。

初始值:

f[1]=1; vis[1]=0;
f[2]=2; vis[2]=0;
f[3]=3; vis[3]=0;
f[4]=4; vis[4]=0;
f[5]=5; vis[5]=0;
f[6]=6; vis[6]=0;

 

第一次操作后:

f[1]=1; vis[1]=0;
f[2]=2; vis[2]=0;
f[3]=2; vis[3]=1;
f[4]=4; vis[4]=0;
f[5]=5; vis[5]=0;
f[6]=6; vis[6]=0;

 


第二次操作后:

f[1]=1; vis[1]=0;
f[2]=2; vis[2]=1;
f[3]=2; vis[3]=1;
f[4]=2; vis[4]=1
f[5]=5; vis[5]=0;
f[6]=6; vis[6]=0;

 


 第三次操作后:

f[1]=1; vis[1]=1;
f[2]=2; vis[2]=1;
f[3]=2; vis[3]=1;
f[4]=2; vis[4]=1;
f[5]=1; vis[5]=1;
f[6]=5; vis[6]=1;

 另附代码:

#include <iostream>  
#include <stdio.h>  
#include <algorithm>  
#include <string.h>  
using namespace std;  
  
const int maxn=10010;
const int maxq=100;   
int f[maxn];
int find(int x)  
{  
    if(f[x]==-1)  
        return x;  
    return f[x]=find(f[x]);  
}  
void unite(int u,int v)  
{  
    int x=find(u);  
    int y=find(v);  
    if(x!=y)  
        f[x]=y;  
}  
  
bool vis[maxn];
int ancestor[maxn];
struct Edge  
{  
    int to,next;  
}edge[maxn*2];  
int head[maxn],tot;  
void addedge(int u,int v)
{  
    edge[tot].to=v;  
    edge[tot].next=head[u];  
    head[u]=tot++;  
}  
  
struct Query  
{  
    int q,next;  
    int index; 
}query[maxq*2];  
int ans[maxn*2];
int h[maxn],tt;  
int Q;
  
void addquery(int u,int v,int index)
{  
    query[tt].q=v;  
    query[tt].next=h[u];  
    query[tt].index=index;  
    h[u]=tt++;  
    query[tt].q=u;
    query[tt].next=h[v];  
    query[tt].index=index;  
    h[v]=tt++;  
}  
  
void init()  
{  
    tot=0;  
    memset(head,-1,sizeof(head));  
    tt=0;  
    memset(h,-1,sizeof(h));  
    memset(vis,0,sizeof(vis));  
    memset(f,-1,sizeof(f));  
    memset(ancestor,0,sizeof(ancestor));  
}  
  
void LCA(int u)  
{  
    ancestor[u]=u;  
    vis[u]=true;  
    for(int i=head[u];i!=-1;i=edge[i].next) 
    {  
        int v=edge[i].to;  
        if(vis[v])  
            continue;  
        LCA(v);  
        unite(u,v);  
        ancestor[find(u)]=u;
    }  
    for(int i=h[u];i!=-1;i=query[i].next)
    {  
        int v=query[i].q;  
        if(vis[v])  
            ans[query[i].index]=ancestor[find(v)];  
    }  
}  
bool flag[maxn];
  
int t;  
int n,u,v;  
  
int main()  
{  
    cin >> n;  
    init();  
    memset(flag,0,sizeof(flag));  
    for(int i=1;i<n;i++)  
    {  
        cin >> u >> v; 
        flag[v]=true; 
        addedge(u,v);  
        addedge(v,u);  
    }  
    cin >> Q;
    for(int i=0;i<Q;i++)  
    {  
        scanf("%d%d",&u,&v);  
        addquery(u,v,i);  
    }  
    int root;  
    cin >> root;
    LCA(root);  
    for(int i=0;i<Q;i++)  
        printf("%d\n",ans[i]);  
    return 0;  
}  
posted @ 2018-02-26 21:40  dgklr  阅读(221)  评论(0编辑  收藏  举报