• lca


    http://acm.hdu.edu.cn/showproblem.php?pid=2586

    无根树转有根树,基于rmq算法计算lca,模板题

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <cmath>
    using namespace std ;
    const int MAX_V=40005 ;//节点数 
    struct edge{int id,to,cost ;} ;//边编号 到达节点 边权值 
    vector <edge> G[MAX_V] ;
    int dp[100005][20] ;
    void makermq(int n,int *tt)
    {
        for(int i=0 ;i<n ;i++)
            dp[i][0]=tt[i] ;
        for(int j=1 ;(1<<j)<=n ;j++)
            for(int i=0 ;i+(1<<j)-1<n ;i++)
                dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]) ;
    } 
    int rmq(int l,int r)
    {
        int k=(int)(log((r-l+1)*1.0)/log(2)) ;
        return min(dp[l][k],dp[r-(1<<k)+1][k]) ;
    }
    int root ;//
    int vs[MAX_V*2-1] ;//按根的dfs序得到的顶点序列 
    int depth[MAX_V*2-1] ;//按根的dfs序得到的顶点序列 对应的深度 
    int id[MAX_V] ;// 对于每个节点,在vs中首次出现的下标 
    int dis[MAX_V] ;//到根节点距离 
    int son[MAX_V] ;//节点的儿子数量  son[i]==0为叶子节点 
    int top[MAX_V] ;//和父节点之间边的编号 
    int fa[MAX_V] ;//记录父亲节点编号 
    void dfs(int v,int p,int d,int &k)
    {
        
        id[v]=k ;
        son[v]=0 ;
        vs[k]=v ;
        depth[k++]=d ;
        for(int i=0 ;i<G[v].size() ;i++)
        {
            edge &e=G[v][i] ;
            if(e.to!=p)
            {
                son[v]++ ;
                fa[e.to]=v ;
                top[e.to]=e.id ; 
                dis[e.to]=dis[v]+e.cost ;
                dfs(e.to,v,d+1,k) ;
                vs[k]=v ;
                depth[k++]=d ;
            }
        }
    }
    void INIT(int V)
    {
        memset(dis,0,sizeof(dis)) ;
        int k=0 ;
        dfs(root,-1,0,k) ;
        makermq(V*2-1,depth) ;
    }
    int lca(int u,int v)
    {
        return vs[rmq(min(id[u],id[v]),max(id[u],id[v]))] ;
    }
    int main()
    {
        int t ;
        scanf("%d",&t) ;
        while(t--)
        {
            int n,m ;
            scanf("%d%d",&n,&m) ;
            for(int i=0 ;i<MAX_V ;i++)
                G[i].clear() ;
            for(int i=0 ;i<n-1 ;i++)
            {
                int a,b,w ;
                scanf("%d%d%d",&a,&b,&w) ;
                G[a].push_back((edge){i,b,w}) ;
                G[b].push_back((edge){i,a,w}) ;
            }
            root=1 ;
            INIT(n) ;
            while(m--)
            {
                int a,b ;
                scanf("%d%d",&a,&b) ;
                int p=lca(a,b) ;
                printf("%d
    ",dis[a]+dis[b]-2*dis[p]) ;
            }
        }
        return 0 ;
    }
    View Code

  • 相关阅读:
    MySQL学习笔记
    Git常用命令
    MacBook Pro m1安装swoole PHP版本7.4
    斐波那契数列实现的2种方法
    归纳一些比较好用的函数
    阶乘的实现
    冒泡排序
    PHP上传图片
    PHPStorm常用快捷键
    DataTables的使用
  • 原文地址:https://www.cnblogs.com/xiaohongmao/p/3783075.html
Copyright © 2020-2023  润新知