1. 程式人生 > >最近公共祖先LCA---線上倍增演算法

最近公共祖先LCA---線上倍增演算法

  線上求LCA,多次詢問。倍增演算法時間複雜度為\left ( n+q \right )\log_{2}n

  1、dfs求每個節點所在層數

void dfs(int u,int root,int d)
{
    int i;
    depth[u]=d;
    fa[u][0]=root;//初始化
    int sz=edge[u].size();
    for(i=0;i<sz;i++)
    {
        int v=edge[u][i].v;
        int w=edge[u][i].w;
        if(v!=root)
        {
            dis[v]=dis[u]+w;
            dfs(v,u,d+1);
        }
    }
}//搜尋出各點的深度,以1為根節點,根節點的深度為0

2、倍增演算法預處理出每個節點向上推移2的j次方後的節點

void bz()
{
    int i,j;
    for(j=1;(1<<j)<=N;j++)
    {
        for(i=1;i<=n;i++)
        {
            fa[i][j]=fa[fa[i][j-1]][j-1];
        }
    }
}

3、查詢最近公共祖先

類似於二分的思想,兩個節點按2的i(1,2,3,4,...)次方向上推移,推移到一定程度,他們的祖先序列完全相同。如果推移一段時間後找到這兩個節點相同的祖先了,那麼這個祖先節點一定是最近公共祖先或者最近公共祖先的祖先,向下搜尋;否則,繼續向上找。

int LCA(int u,int v)
{
    if(depth[u]<depth[v])
        swap(u,v);//保證深度較大的為u
    int dc=depth[u]-depth[v];
    int i;
    for(i=M-1;i>=0;i--)
        if((1<<i)&dc)
            u=fa[u][i];
    if(u==v)
        return u;//u移到了和v一個點,該點就是他們的最近公共祖先
    for(i=M-1;i>=0;i--)//u和v現在已經在一層,他們往上走幾層之後祖先序列相同
    {//找到最小的不滿足相同序列的點,
        if(fa[u][i]!=fa[v][i])
        {
            u=fa[u][i];
            v=fa[v][i];
        }
    }
    return fa[u][0];//最後,最近公共祖先為找到的點的祖先
}