1. 程式人生 > >最近公共祖先 LCA

最近公共祖先 LCA

一、基本演算法

       1、 Tarjan演算法基於深度優先搜尋的框架,對於新搜尋到的一個節點,首先建立有這個節點構成的集合,再對當前節點的每一個子樹進行搜尋,每搜尋完一個子樹,則確定子樹內的LCA詢問都已解決。其他的LCA詢問的結果必然在這個子樹之外,這時把子樹所形成的集合與當前節點的集合合併,並將當前節點設為這個集合的祖先。之後繼續搜尋下一棵子樹。

       2、虛擬碼:

            (1)建立以u為代表的集合。

            (2)遍歷與u相連的節點v,如果v沒有被訪問過,對於v使用LCA演算法,結束後,將v的集合併入u的集合。

            (3)對於與u有關的詢問(u, v), 如果v被訪問過,則結果就是v所在的集合的代表元素。

       3、程式碼:

int p[MAXX];
int head[MAXX];   //前向星
int qhead[MAXX];  // 表示詢問
struct node
{
    int to;
    int lca;
    int next;
};
node edge[MAXX];   // 邊的資訊
node qedge[MAXX];  // 表示詢問
int Find(int x)
{
    if (p[x] != x)
        p[x] = Find(p[x]);
    return p[x];
}

bool vis[MAXX];
void LCA(int u)
{
    p[u] = u;
    int k;
    vis[u] = true;
    for (k=head[u]; k!=-1; k=edge[k].next)
    {
        if (!vis[edge[k].to)
        {
            LCA(edge[k].to);
            p[edge[k].to] = u;
        }
    }
    
    for (k=qhead[u]; k!=-1; k = qedge[k].next)
    {
        if (vis[qedge[k].to])
        {
            qedge[k].lca = Find(qedge[k].to);
            qedge[k^1].lca = qedge[k].lca;
        }
    }
}