zoukankan      html  css  js  c++  java
  • [luogu3379]最近公共祖先(树上倍增求LCA)

    题意:求最近公共祖先。

    解题关键:三种方法,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
    ",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
    ",lca(u,v));
        }
        return 0;
    }
  • 相关阅读:
    基本几何变换——以鼠标为中心进行缩放
    jquery radio/checkbox change 事件不能触发的问题
    CCF YOCSEF“面向科学的大数据管理与分析”报告会即将举行
    mac iTunes启动失败,声称iTunes文件夹被锁定
    opencv2.3 + visual studio 2010 编译配置方法
    Qt QGLWidget 不能够实时刷新的问题
    在mac os x中建立事件钩子
    二叉树前序、中序、后序、层次遍历
    CRC从原理到实现
    异步FIFO的FPGA实现
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/10352437.html
Copyright © 2011-2022 走看看