求lca

lca模板

也就是求树上两点的最近公共祖先。

我们采用树上倍增。

将两点跳至同一高度。

一起向上跳。

bfs(或dfs)预处理节点深度及节点的2的几次方的父亲。

代码:

#include <cstdio>
#include <queue>
#include <cmath>

using namespace std;

typedef long long int ll;
const int maxn=100005;
int n,m,s,tot,head[maxn],d[maxn],f[maxn][35],w;
struct node{
    int to,nxt;
}t[maxn];
inline void add(const int x,const int y){
    t[++tot].to=y;t[tot].nxt=head[x];
    head[x]=tot;
}
queue<int>q;
inline void bfs(const int s){
    q.push(s);
    d[s]=1;
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=t[i].nxt){
            int y=t[i].to;
            if(d[y])continue;
            d[y]=d[x]+1;
            f[y][0]=x;
            for(int j=1;j<=w;j++){
                f[y][j]=f[f[y][j-1]][j-1];
            }
            q.push(y);
        }
    }
}
inline int lca(int x,int y){
    if(d[y]>d[x])swap(x,y);
    for(int i=w;i>=0;i--){
        if(d[f[x][i]]>=d[y]){
            x=f[x][i];
        }
    }
    if(x==y)return x;
    for(int i=w;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;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    w=(int)(log(n)/log(2))+1;
    bfs(s);
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",lca(x,y));
    }
    return 0;
}

 

posted @ 2020-08-21 18:12  weijianzhen  阅读(112)  评论(0编辑  收藏  举报