LCA hdu2586

hdu 2586
dp[x][i]表示节点i往上走2^i次所到达的祖先,那么不难写出转移方程:
dp[x][i]=dp[dp[x][i-1]][i-1];
然后在求LCA的时候,有这样一个性质:(假设a和b深度一样)
于是求法就渐渐的现行了:
1. 把a和b移到同一深度(设deep[x]为节点x的深度),假设deep[a]<=deep[b],所以我们的目的是把b向上 移动i=(deep[b]-deep[a])层,那么,由于之前有预处理的dp数组,我们把i写成二进制形势,然后利用dp数 组来在log n的复杂度中完成;
2. 寻找a和b的LCA下一层的两个祖先。利用之前的那个性质,再利用倍增,如果a和b的第2^k个祖先不是
同一个,那么a=dp[a][k],b=dp[b][k];当然在这之前要实现确定k的最大值,从大往小处理下去。最终的
结果就是dp[a][0];
注意点:如果a和b在调节深度之后已经是同一个祖先的,那么直接返回a或者b。

//#include <bits/stdc++.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<stdlib.h>
#include<time.h>
#include <iomanip>
#define lowbit(x) (x&(-x))
#define inf  0x7fffffff
#define linf 0x7fffffffffffffff
#define fil(x,y) memset(x,y,sizeof(x))
#define fup(i,x,y) for(int i=(x);i<=(y);i++)
#define fdn(i,x,y) for(int i=(x);i>=(y);i--)
#define sp(x) setprecision(x)
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d%d",&n,&m)
#define sddd(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define sld(n) scanf("%lld",&n)
#define sldd(n,m) scanf("%lld%lld",&n,&m)
#define slddd(n,m,k) scanf("%lld%lld%lld",&n,&m,&k)
#define sf(n) scanf("%lf",&n)
#define sff(n,m) scanf("%lf%lf",&n,&m)
#define sfff(n,m,k) scanf("%lf%lf%lf",&n,&m,&k)
#define sc(n) scanf("%s",n)
#define pf(x) printf("%d\n",x)
#define pfl(x) printf("%lld\n",x)
#define pff(x) printf("%lf\n",x)
#define debug printf("!!\n");
#define N 1000005
#define M 4000009
#define pi acos(-1)
#define eps 1e-2
//cout.setf(ios::fixed);
//freopen("out.txt","w",stdout);// freopen("in.txt","r",stdin);
using namespace std;
typedef long long  ll;
typedef double db;
int n,s;
struct node
{
    int go,t;
};
int fa[100005],deep[100005],dp[100005][17],dis[100005];
vector<node> q[100005];
void dfs(int x,int dep)
{
    deep[x]=dep;
    dp[x][0]=fa[x];
    for(int i=1;(1<<i)<deep[x];i++)
        dp[x][i]=dp[dp[x][i-1]][i-1];
    for(int i=0;i<q[x].size();i++)
    {
        node tp=q[x][i];
        if(tp.go!=fa[x])
        {
            dis[tp.go]=dis[x]+tp.t;
            fa[tp.go]=x;
            dfs(tp.go,dep+1);
        }
    }
}
int lca(int a,int b)
{
    if(deep[a]>deep[b]) swap(a,b);
    int k=deep[b]-deep[a];

    for(int i=0;i<=19;i++)
        if((1<<i)&k) b=dp[b][i];


    for(int i=19;i>=0;i--)
        if(dp[a][i]!=dp[b][i]) a=dp[a][i],b=dp[b][i];
    if(a==b) return a;
    return dp[a][0];
}
int main()
{
    int tt;
    sd(tt);
    while(tt--)
    {
        fil(dis,0);
        fil(dp,0);
        fil(deep,0);
        fil(fa,0);
        int n,m;
        sdd(n,m);
        fup(i,1,n-1)
        {
            int x,y,z;
            sddd(x,y,z);
            q[x].push_back(node{y,z});
            q[y].push_back(node{x,z});
        }
        dfs(1,1);
        while(m--)
        {
            int x,y;
            sdd(x,y);
            pf(dis[x]+dis[y]-2*dis[lca(x,y)]);
        }
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值