LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。 ———来自百度百科
**
LCA模板
**
以后遇到LCA问题可以直接拿来用
时间复杂度:预处理(nlogn)每次询问(logn)
#pragma GCC optimize(3,"Ofast","inline") //G++
#pragma comment(linker, "/STACK:102400000,102400000")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include <functional>
#define TEST freopen("in.txt","r",stdin);
#define mem(a,x) memset(a,x,sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
typedef unsigned long long ull; // %llu
const double PI = acos(-1.0);
const double eps = 1e-6;
const int mod=1e9+7;
const int INF = -1u>>1;
const int maxn = 5e5+5;
int n,m,root;
int depth[maxn],father[maxn][30],lg[maxn],len[maxn];
//depth为节点深度 father[i][j]为i节点向上跳2^i时所在的节点 len节点为到根节点的距离
//主要说一下 lg[x]为x在2进制下的位数 比如lg[5]=3,也就是101。所以我们第一步跳,只需要从2^(lg[5]-1)开始跳 (注意需要减1) 最开始能跳最大的步数就是2的n次方 这个n就是位数减1,仔细想想
//第一次跳4 (2进制下为100) 第二次不跳 第三次跳1(001) 即100+1=101可以优化时间
struct node
{
int to,len;
};
vector<node>edge[2*maxn];
void add(int x,int y,int len)
{
edge[x].push_back(node{y,len});
edge[y].push_back(node{x,len});
}//建边
void dfs(int u,int fa,int lenth)
{
father[u][0]=fa; //father[u][0]就是u跳一个节点 也就是u的父亲节点
depth[u]=depth[fa]+1; //儿子节点的深度为父亲节点的深度加1
len[u]=len[fa]+lenth; //到根的长度
for(int i=1; (1<<i)<=depth[u]; i++) //关键 大概意思就是 u跳2^i步等于u跳2^(i-1)步在跳2^(i-1)步
{
father[u][i]=father[father[u][i-1]][i-1];
}
for(int i=0; i<edge[u].size(); i++) //深搜下
{
node v=edge[u][i];
if(v.to!=fa)
dfs(v.to,u,v.len);
}
}
int lca(int x,int y)
{
if(depth[x]<depth[y]) //保证x的深度大于y
swap(x,y);
// for(int i=(int)(log2(n*1.0))+1;;i>=0;i--) //这种做法可能会浪费一些时间,看题解写到了预处理lg感觉还巧妙
// {
// if(不在同一深度)
// 高深度向低深度跳
// if(在同一深度)
// 跳之后的两个节点不同可以跳
// }
while(depth[x]>depth[y])
{
x=father[x][lg[depth[x]-depth[y]]-1]; //偷学而来
}
if(x==y)return x; //如果深度相同时两个节点为同一个不用在向上搜了
for(int i=lg[depth[x]]-1; i>=0; i--) //深度不同时两个点同时向上搜 当向上搜到的节点不相等的时候证明可能到达 更新节点
{
if(father[x][i]!=father[y][i])
{
x=father[x][i];
y=father[y][i];
}
}
return father[x][0]; //返回最后到达节点的父亲
}
int main()
{
// TEST
ios;
for(int i=1; i<=40000; i++) //预先算出log_2(i)+1的值,用的时候直接调用就可以了,优化时间
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
int T;
cin>>T;
while(T--)
{
cin>>n>>m;
for(int i=1; i<=n-1; i++)
{
int x,y,len;
cin>>x>>y>>len;
add(x,y,len);
root=x;
}
dfs(root,0,0); //随便用一个点设为根节点
while(m--)
{
int x,y;
cin>>x>>y;
int ans=len[x]+len[y]-2*len[lca(x,y)]; //两点间距离就是x到根节点的距离加上y到根节点的距离减去2倍的lca到根节点的距离
cout<<ans<<"\n";
}
mem(len,0);
}
}