HDU 2586 ST表求LCA 树上距离

本文详细介绍了ST表的构建方法及其递推公式,并通过一个具体的AC代码示例展示了如何利用ST表来高效求解树上的最近公共祖先(LCA)问题及节点间的距离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ST表递推公式:
st[i][j]=st[st[i][j−1]][j−1]st[i][j] = st[st[i][j-1]][j-1]st[i][j]=st[st[i][j1]][j1]
表示iii向上跳深度为2j2^j2jiii向上跳深度为2j−12^{j-1}2j1再向上跳深度为2j−12^{j-1}2j1

树上距离公式:
dis[a,b]=dis[a]+dis[b]−2dis[lca(a,b)]dis[a,b] = dis[a]+dis[b]-2dis[lca(a,b)]dis[a,b]=dis[a]+dis[b]2dis[lca(a,b)]

AC代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 4e4+500;

int n,m,beg[maxn],tot,dep[maxn],fa[maxn],dis[maxn];
struct node{int to,nex,val;}edge[maxn*2];//链式前向星
int st[maxn][21];//ST表

inline void add(int u,int v,int val){
    edge[++tot].to = v;
    edge[tot].nex = beg[u];
    edge[tot].val = val;
    beg[u] = tot;
}

void dfs(int now,int f,int deep){
    fa[now] = f , dep[now] = deep;
    for(int i=beg[now];i;i=edge[i].nex){
        int nx = edge[i].to;
        if(nx==f) continue;
        dis[nx] = dis[now]+edge[i].val;
        dfs(nx,now,deep+1);
    }
}

void init(){
    for(int j=0;(1<<j)<=n;j++)
        for(int i=1;i<=n;i++)
            st[i][j] = j==0?fa[i]:-1;
    for(int j=1;(1<<j)<=n;j++)	//j表示向上跳2^j步
        for(int i=1;i<=n;i++)	//i表示节点编号
            if(st[i][j-1]!=-1)
                st[i][j] = st[st[i][j-1]][j-1];
}

int lca(int a,int b){
    if(dep[a]<dep[b]) swap(a,b);	//指定a节点为深度小的
    int i,j;
    for(i=0;(1<<i)<=dep[a];i++) ;   //找到最大能跳多少
    i--;
    for(j=i;j>=0;j--)    //跳到同样深度
        if(dep[a]-(1<<j)>=dep[b])
            a = st[a][j];
    if(a==b) return a;
    for(j=i;j>=0;j--){  //一起向上跳
        if(st[a][j]!=-1&&st[a][j]!=st[b][j])
            a = st[a][j] , b = st[b][j];
    }
    return fa[a];	//!一定会少跳一次
}

int main(){
    int _;
    scanf("%d",&_);
    while(_--){
        tot = 0;
        for(int i=1;i<=n;i++)   
            beg[i]=0;			//初始化
        scanf("%d%d",&n,&m);
        for(int i=1,u,v,val;i<=n-1;i++){
            scanf("%d%d%d",&u,&v,&val);
            add(u,v,val) , add(v,u,val);
        }
        dis[1] = 0;		//指定1为根
        dfs(1,0,1);		//查询深度,父亲,树上距离
        init();			//ST表初始化
        while(m--){
            int a,b;
            scanf("%d%d",&a,&b);
            printf("%d\n",dis[a]+dis[b]-2*dis[lca(a,b)]);//查询距离
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值