图论学习7-最近公共祖先(LCA)

最近公共祖先(LCA)

LCA问题:在有根树中,找出某两个结点 u 和 v 最近的公共祖先
算法:倍增法(大的不行试小的,小的不行试更小的)
算法思想:分治。
算法流程当已知两个点在树中的深度时,先让较深的结点向上走,直到两个结点深度一样;二分找出离他们最近的公共祖先。我们记一个结点的父结点为它的2^0=1倍祖先,它的父结点的父结点为它的2^1=2倍祖先,以此类推。接下来开始描述倍增算法的具体流程。
1.:在树上预处理每个结点的深度和0倍祖先,也就是每个结点的父结点。用 d 数组来表示每个结点的深度, p[v][h] 表示结点v的h倍祖先的结点编号。 d 数组中的元素初始为 -1。初始化完成后,p[a][0]保存的是a的第 2^0=1 倍祖先结点,即它的父结点。时间复杂度O(V)
2.:倍增计算各个点的2^j祖先是谁,其中,1倍祖先就是父亲,2倍祖先是父亲的父亲,以此类推。该点2^j祖先也就是该点2^j-1祖先的2^j-1祖先。在这一步中,2^level 表示的是祖先的倍数。很显然i,2^j的 倍祖先就是i的2^j-1祖先的2^j-1祖先。时间复杂度为O(VlogV)。
3.第三步(查询):首先,深度大的点往上爬,直到与深度小的点在同一层。若此时两结点相同直接返回此结点,即最近公共祖先 LCA。这意味着其中一个结点是另一个结点的祖先结点。
否则,利用倍增思想,同时让x和y二分地向上找,直到找到深度相等且最小的x和y的祖先x’,y’满足x’!=y’ 。此时他们的父结点p[x’][0]即为x和y的最近公共祖先 LCA。
*这个算法学的时候会觉得很迷2手动走上两遍就会明白了。
模板代码

#include 
#include 
#include  
using namespace std;
const int MAX_N=100000;
const int MAX_M=1000000;
int isleave[100050];
struct edge{
    int v,next;
}E[MAX_M];
int p[MAX_N],eid;
void init(){
    memset(p,-1,sizeof(p));
    memset(isleave,0,sizeof(isleave));
    eid=0;
}
void insert(int u,int v){
    E[eid].v=v;
    E[eid].next=p[u];
    p[u]=eid++;
}
int d[MAX_N],fa[MAX_N][20];
void dfs(int u){
    for(int i=p[u];i!=-1;i=E[i].next){
        if(d[E[i].v]==-1){
            d[E[i].v]=d[u]+1;
            fa[E[i].v][0]=u;
            dfs(E[i].v);
        }
    }

}

int lca(int x,int y){
    int i,j;
    if(d[x]for(i=0;(1<for(j=i;j>=0;j--){
        if(d[x]-(1<=d[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;
    init();
    cin>>n;
    for(int i=0;i1;i++)
    {
        int u,v;
        cin>>u>>v;
        insert(u,v);
        insert(v,u);
        isleave[v]=1;
    }
    memset(d,-1,sizeof(d));
    int root;
    for(int i=1;i<=n;i++)
        {
        if(isleave[i]==0){
            root=i;
            break;
        }
    }
    d[root]=1;
    dfs(root);
    for(int level=1;(1<for(int i=1;i<=n;i++){
            fa[i][level]=fa[fa[i][level-1]][level-1];
        }
    }
    int q;
    cin>>q;
    while(q--){
        int a,b;
        cin>>a>>b;
        cout<return 0;
}

你可能感兴趣的:(算法学习总结,#,图论)