HDU 2586 How far away ?【LCA】

題目來源:http://acm.hdu.edu.cn/showproblem.php?pid=2586
在這裏插入圖片描述
★就是這題讓我入坑了 LCA ,目前只會 倍增法求LCA ,所以題解也是用的倍增法(不過我看其他題解沒看到用倍增的


思路:

不考慮點之間的距離(設每個點的距離爲1)假設要 求 點a到點b 的距離,且已知 點a和點b 的LCA是 點t
現在用dep[ i ]表示點i的深度,那麼 點a到點b的距離=dep[ a ] + dep[ b ] - 2*dep[ t ] 不明白的話可以手動畫圖輔助理解
但是本題加了點之間的距離,其實也沒變多複雜,只需要把 點i到根的距離記錄下來就好了(記爲dis[ i ])
故答案爲 dis[a]+dis[b]-2*dis[lca(a,b)]


代碼:

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<deque>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=4e4+5;
const int sz=1<<16;
const int inf=2e9;
const int mod=1e9+7;
const double pi=acos(-1);
typedef long long LL;
int n,m,cnt;
struct node
{
    int next;
    int to;
    int v;
}edge[maxn<<1];
int head[maxn],dep[maxn],dis[maxn];
int fa[maxn][22],lg[maxn];
template<class T>
inline void read(T &x)
{
    char c;x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
void add_edge(int a,int b,int c)
{
    edge[++cnt].to=b;
    edge[cnt].v=c;
    edge[cnt].next=head[a];
    head[a]=cnt;
}
void dfs(int p,int f,int dist)           //p爲當前點 , f爲其父節點 , dist爲目前的距離
{
//    cout<<p<<'x'<<endl;
    dep[p]=dep[f]+1;
    dis[p]=dist;
    fa[p][0]=f;
    for(int i=1;(1<<i)<=dep[p];i++){
        fa[p][i]=fa[fa[p][i-1]][i-1];
    }
    for(int i=head[p];i;i=edge[i].next){
        if(edge[i].to!=f)
        dfs(edge[i].to,p,dist+edge[i].v);
    }
}
int lca(int a,int b)
{
    if(dep[a]<dep[b]) swap(a,b);
    while(dep[a]>dep[b]){
        a=fa[a][lg[dep[a]-dep[b]]-1];
    }
    if(a==b) return a;
    for(int i=lg[dep[a]]-1;i>=0;i--){
        if(fa[a][i]!=fa[b][i])
            a=fa[a][i],b=fa[b][i];
    }
    return fa[a][0];
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int s,a,b,c;
        cnt=0;
        memset(head,0,sizeof head);

        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++){
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a,b,c);
            add_edge(b,a,c);
        }
        dfs(1,0,0);
        for(int i=1;i<=n;i++)
            lg[i]=lg[i-1]+(1<<lg[i-1]==i);
        while(m--){
            scanf("%d%d",&a,&b);
            printf("%d\n",dis[a]+dis[b]-2*dis[lca(a,b)]);
        }
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章