码迷,mamicode.com
首页 > 其他好文 > 详细

[luogu3379]最近公共祖先(树上倍增求LCA)

时间:2019-02-05 09:24:19      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:iostream   ==   wap   span   dfs   space   def   stream   continue   

题意:求最近公共祖先。

解题关键:三种方法,1、st表 2、倍增法 3、tarjan

此次使用倍增模板

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
int n,m,root,cnt,u,v,head[500005],dep[500005],fa[500005][21];
struct edge{
    int nxt;
    int to;
}e[1000005];
void add_edge(int u,int v){//单向
    e[cnt].to=v;
    e[cnt].nxt=head[u];
    head[u]=cnt++;
}
void dfs(int u){
    for(int i=1;(1<<i)<=dep[u];i++){
        fa[u][i]=fa[fa[u][i-1]][i-1];
    }
    for(int i=head[u];~i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa[u][0]) continue;
        fa[v][0]=u;
        dep[v]=dep[u]+1;
        dfs(v);
    }
}
int lca(int u,int v){
    if(dep[u]<dep[v]) swap(u,v);
    int d=dep[u]-dep[v];
    for(int i=0;(1<<i)<=d;i++) if(d&(1<<i)) u=fa[u][i];//转化到两节点深度相同,类似于快速幂的思想
    if(u==v) return u;
    for(int i=20;i>=0;i--){
        if(fa[u][i]!=fa[v][i]){
            u=fa[u][i];
            v=fa[v][i];
        }
    }
    return fa[u][0];
}
int main(){
    memset(head,-1,sizeof head);
    scanf("%d%d%d",&n,&m,&root);
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        add_edge(u,v);
        add_edge(v,u);
    }
    dfs(root);
    while(m--){
        scanf("%d%d",&u,&v);
        printf("%d\n",lca(u,v));
    }
    return 0;
}

 2、熟悉的树dp方式

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
int n,m,root,cnt,u,v,head[500005],dep[500005],par[500005][21];
struct edge{
    int nxt;
    int to;
}e[1000005];
void add_edge(int u,int v){//单向
    e[cnt].to=v;
    e[cnt].nxt=head[u];
    head[u]=cnt++;
}
void dfs(int u,int fa){
    for(int i=1;(1<<i)<=dep[u];i++){
        par[u][i]=par[par[u][i-1]][i-1];
    }
    for(int i=head[u];~i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa) continue;
        par[v][0]=u;
        dep[v]=dep[u]+1;
        dfs(v,u);
    }
}
int lca(int u,int v){
    if(dep[u]<dep[v]) swap(u,v);
    int d=dep[u]-dep[v];
    for(int i=0;(1<<i)<=d;i++) if(d&(1<<i)) u=par[u][i];//转化到两节点深度相同,类似于快速幂的思想
    if(u==v) return u;
    for(int i=20;i>=0;i--){
        if(par[u][i]!=par[v][i]){
            u=par[u][i];
            v=par[v][i];
        }
    }
    return par[u][0];
}
int main(){
    memset(head,-1,sizeof head);
    scanf("%d%d%d",&n,&m,&root);
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        add_edge(u,v);
        add_edge(v,u);
    }
    dfs(root,-1);
    while(m--){
        scanf("%d%d",&u,&v);
        printf("%d\n",lca(u,v));
    }
    return 0;
}

 

[luogu3379]最近公共祖先(树上倍增求LCA)

标签:iostream   ==   wap   span   dfs   space   def   stream   continue   

原文地址:https://www.cnblogs.com/elpsycongroo/p/10352437.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!