之前撸了一发离线的lca 就是tarjan算法
这次来一发倍增lca
对于两个节点的lca 这两个节点要到同层 再跳跃倍增找到祖先
其本质是跳跃 2^i ==2^(i-1)+2^(i-1)
文字表述是我跳到八代祖先 我就先跳到四代祖先 再跳四代祖先
#include<cstring>
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=40020;
int dis[maxn];//根到子节点的距离
int depth[maxn];//每个节点的深度
int p[maxn][20];
int n,m;
struct node
{
int to,value;
};
vector<node> vec[maxn];
void dfs(int u,int step,int father)
{
//标个粑粑 顺便把节点搜索出来
depth[u]=step;
p[u][0]=father;
for(int i=0;i<vec[u].size();i++)
{
int v=vec[u][i].to;
int w=vec[u][i].value;
if(v!=father)
{
dis[v]=dis[u]+w;
dfs(v,step+1,u);
}
}
}
void init_f()
{
for(int i=1;(1<<i)<=n;++i)//初始化到最坏情况 就是所有子节点都在一侧
{
for(int j=1;j<=n;++j)
{
p[j][i]=p[p[j][i-1]][i-1];
}
}
}
/*int lca(int u,int v)
{
if(u==v) return u;
if(depth[u]<depth[v]) swap(u,v);
int d=depth[u]-depth[v];
for(int i=0;(1<<i)<=d;i++)
{
if((1<<i)&d) u=p[u][i];
}
for(int i=(int)log2(n);i>=0;i--)
{
if(p[u][i]!=p[v][i])
{
u=p[u][i];
v=p[v][i];
}
}
return p[u][0];
}*/
int lca(int u,int v)
{
if(depth[u]<depth[v]) swap(u,v);
int d=depth[u]-depth[v];
for(int j=19;j>=0;--j){
if((1<<j)&d) //当d为3(11) 1<<j 为 10 就可以跳此时j为1. 当j为0时 1<<j 为1 就总共跳了3次
//Q:为毛不会重复跳跃同样的次数 如:当d为(1xx)时,跳6下(110) 和4下(100)都会进入if啊?
//A:他这是跳完之后就直接把这个二进制位直接移走了呀 所以不会重复跳
u=p[u][j];
}
/*
之前这一段 我想的跳到同层的操作是
for(int i=0;(1<<i)<=d;i++)
if((1<<j)&d)
u=p[u][j];
但其实是错误的
从1开始起跳
假如我要跳到上八代祖先是永远也不可能实现的
因为它是这样跳的嘛 1 2 4 8
奇数只有一个 根本凑不到8
*/
if(u==v){
return u;
}
for(int i=(int)log2(n);i>=0;--i){//这里的logn是最坏情况 即所有元素都在树的一侧
if(p[u][i]!=p[v][i]){ //所以直接从高位起跳 加速
//Q:跳过头了咋办
//A:跳过头的元素值是相同的 进不了if 所有u v不会更新
//Q:敲里吗 为毛元素是相同的 博主你快讲清楚
//A:init_f里 假如设根节点为第0层 第一层的节点假如跳两下就过头了
//那么p[x][1]=p[p[x][0]][0] 其值还是根节点的父亲 无论跳多少次都是根节点的父亲
u=p[u][i];
v=p[v][i];
//所以u v的值始终不同 但会随着程序的运行接近lca
}
}
return p[u][0];
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
vec[i].clear();
}
for(int i=0;i<n-1;i++)
{
node tem;
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
tem.to=v;
tem.value=w;
vec[u].push_back(tem);
tem.to=u;
vec[v].push_back(tem);
}
dis[1]=0;
dfs(1,0,0);
init_f();
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
int ans=dis[u]+dis[v]-2*dis[lca(u,v)];
printf("%d\n",ans);
}
}
}