LCA有多个方法可以求解,此文章记录树上倍增法解决LCA问题
类似于RMQ,通过bfs用二维dp数组通过二进制记录 i 的 2^j 祖先是谁 预处理复杂度n*log
模板已POJ 2586 为例
http://acm.hdu.edu.cn/showproblem.php?pid=2586
d数组记录深度,pre记录根到当前点的权值和
#include <bits/stdc++.h>
//#include <iostream>
//#include <queue>
//#include <cmath>
//#include <cstring>
//#include <algorithm>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef __int128 bll;
const ll maxn = 4e4+100;
const ll mod = 1e9+7;
const ld pi = acos(-1.0);
const ll inf = 1e18;
const ld eps = 1e-5;
const ld e = exp(1);
ll T,n,m,dp[maxn][30],d[maxn],pre[maxn],maxd;
vector< pair<ll,ll> >G[maxn];
queue<ll>Q;
void bfs()
{
Q.push(1); //可以更改根节点
d[1] = 1;
while(!Q.empty())
{
ll now = Q.front();
Q.pop();
for(ll i = 0; i < G[now].size(); i++)
{
ll next = G[now][i].first;
if(d[next] == 0) //未访问过
{
d[next] = d[now]+1;
pre[next] = pre[now] + G[now][i].second;
dp[next][0] = now;
for(ll j = 1; j <= maxd; j++) //倍增处理祖先节点
dp[next][j] = dp[ dp[next][j-1] ][j-1];
Q.push(next);
}
}
}
return ;
}
ll query(ll x,ll y)
{
if(d[x] > d[y]) //x浅 y深
swap(x,y);
for(ll i = maxd; i >= 0; i--) //将y与x调到同一层 (因为i在递减)
{
if(d[ dp[y][i] ] >= d[x])
{
y = dp[y][i];
}
}
if(x == y)
return x;
for(ll i = maxd; i >= 0; i--) //开始寻找祖先
{
if(dp[x][i] != dp[y][i])
{
x = dp[x][i];
y = dp[y][i];
}
}
return dp[x][0];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin >> T;
while(T--)
{
memset(dp,0,sizeof(dp));
memset(pre,0,sizeof(pre));
memset(d,0,sizeof(d));
while( !Q.empty() )
{
Q.pop();
}
cin >> n >> m;
maxd = ll( log(n)/log(2) )+1;
for(ll i = 1; i < n; i++)
{
ll x,y,z;
cin >> x >> y >> z;
G[x].push_back( make_pair( y,z ) );
G[y].push_back( make_pair( x,z ) );
}
bfs();
//cout << dp[8][1] << endl;
while(m--)
{
ll a,b;
cin >> a >> b;
cout << pre[a] + pre[b] - 2*pre[ query(a,b) ] << endl;
}
for(ll i = 1; i <= n; i++)
{
G[i].clear();
}
}
return 0;
}