[luogu 3379]最近の公的祖先(樹上倍増LCAを求める)

11487 ワード

最近の公共の祖先を求める.
問題を解く鍵:3つの方法、1、st表2、倍増法3、tarjan
今回は倍増テンプレートを使います(1つ目、2つ目は純粋に習慣です)
#include
#include
#include
#include
#include
#include
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<){
        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<if(d&(1<//
    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){
        scanf("%d%d",&u,&v);
        add_edge(u,v);
        add_edge(v,u);
    }
    dfs(root);
    while(m--){
        scanf("%d%d",&u,&v);
        printf("%d
",lca(u,v)); } return 0; }

2、おなじみのツリーdp方式
#include
#include
#include
#include
#include
#include
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<){
        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<if(d&(1<//
    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){
        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
",lca(u,v)); } return 0; }

 
転載先:https://www.cnblogs.com/elpsycongroo/p/10352437.html