【模板】最近公共祖先(LCA)(倍增做法)

题目描述

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入格式

第一行包含三个正整数 N,M,S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来 N1 行每行包含两个正整数 x,y,表示 x 结点和 y 结点之间有一条直接连接的边(数据保证可以构成树)。

接下来 M 行每行包含两个正整数 a,b,表示询问 a 结点和 b 结点的最近公共祖先。

输出格式

输出包含 M 行,每行包含一个正整数,依次为每一个询问的结果。

说明/提示

对于 30% 的数据,N10,M10。

对于 70% 的数据,N10000,M10000。

对于 100% 的数据,N500000,M500000。


模板题LCA 指路查看网页第一篇题解

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int N=0,n,m,s,dep[600001],lg[600001],last[5000001],f[600001][51];
struct node{
    int next,to;
}a[5000001];
void add(int UU,int VV){
    a[++N].to=VV;
    a[N].next=last[UU];
    last[UU]=N;
}
void dfs(int me,int father){//预处理
    f[me][0]=father;
    dep[me]=dep[father]+1;
    for(int i=1;i<=lg[dep[me]];i++) f[me][i]=f[f[me][i-1]][i-1];///意思是now的2^i祖先等于now的2^(i-1)祖先的2^(i-1)祖先 
                                                                 //2^i = 2^(i-1) + 2^(i-1)
    for(int i=last[me];i;i=a[i].next)
        if(a[i].to!=father) dfs(a[i].to,me);
}
int LCA(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    while(dep[x]>dep[y]) x=f[x][lg[dep[x]-dep[y]]-1];
    if(x==y) return x;
    for(int i=lg[dep[x]]-1;i>=0;i--)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
int main(){
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=n-1;i++){
        int X,Y;
        scanf("%d%d",&X,&Y);
        add(X,Y);
        add(Y,X);
    }
    for(int i=1;i<=n;i++) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
    dfs(s,0);
    while(m--){
        int A,B;
        scanf("%d%d",&A,&B);
        printf("%d\n",LCA(A,B));
    }
}

 

 

 

 

posted @ 2020-08-21 09:53  latent_Lin  阅读(134)  评论(0)    收藏  举报