测试数据
1 10 1
1 2 2
1 4 4
2 3 3
2 5 6
3 7 1
3 8 2
5 6 3
6 9 2
4 10 4
9 10
终于造了什么事树上倍增了下午考pat。。。哭卿卿
代码理解来自 自己又加了备注。。。。 建议模拟一下
https://blog.csdn.net/a601025382s/article/details/10615039
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
const int maxn=40004;
struct node{
int to,w;
node(int a=0,int b = 0){to=a;w=b;}
};
vector<node>e[maxn];
int f[maxn],dis[maxn],deep[maxn],p[maxn][20],n;
void dfs(int u,int pre,int t)
{
int i,num;
deep[u]=t;//深度
f[u]=pre;//父节点
num=e[u].size();
for(i=0;i<num;i++)
{
int v=e[u][i].to;
if(v!=pre)
{
dis[v]=dis[u]+e[u][i].w;//距离跟的距离
dfs(v,u,t+1);
}
}
}
void init()
{
//p[i][j]表示i结点的第2^j祖先
int i, j;
for(j = 1;(1 << j) <= n; j++)
for(i = 1;i <= n; i++)
p[i][j] = -1; //都初始化为-1
for(i = 1;i <= n; i++)
p[i][0] = f[i];
for(j = 1;(1<<j) <= n;j ++)
{
for(i = 1;i <= n; i++)
{
if(p[i][j-1] != -1)
p[i][j] = p[p[i][j-1]][j-1];//i的第2^j祖先就是i的第2^(j-1)祖先的第2^(j-1)祖先
}
}
}
int lca(int a,int b)//最近公共祖先
{
int i,j;
if(deep[a] < deep[b])
swap(a,b);
for(i = 0;(1 << i) <= deep[a]; i++);
i--;//其实小于也行等于也好
//使a,b两点的深度相同
for(j = i;j >= 0;j--)
{
if(deep[a]-(1<<j)>=deep[b])
{
a = p[a][j];
}
} //找到与b同层的或者说 b没有同层的 那么就找他的上一层 不用担心p[a][j]是否等于-1 肯定有
if(a == b)
return a;
//倍增法,每次向上进深度2^j,找到最近公共祖先的子结点
for(j = i;j >= 0; j--)
{
if(p[a][j] != -1 && p[a][j] != p[b][j])
{
a = p[a][j];
b = p[b][j];
}
}
/*如果说都是相等的话 那么说明a b在两个子树的左右子树下面 所以直接返回一个子树的根节点就行
如果说是有不相等的话 那么就两个节点各自更新成他们的p[a][j] 和 p[b][j]
*/
return f[a];
}
int main()
{
int m,i,a,b,c,ans;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)e[i].clear();
for(i=1;i<n;i++)
{
scanf("%d%d%d",&a,&b,&c);
e[a].push_back(node(b,c));
e[b].push_back(node(a,c));
}
dis[1]=0;
dfs(1,-1,0);//找到各点的深度和各点的父节点以及距离根的距离
// cout<<"dis"<<endl;
// for(int i = 0 ; i <= n ; i ++)
// printf("%d%c",dis[i]," \n"[i==n]);
// cout<<"deep"<<endl;
// for(int i = 0 ; i <= n ; i ++)
// printf("%d%c",deep[i]," \n"[i==n]);
// cout<<"f"<<endl;
// for(int i = 0 ; i <= n ; i ++)
// printf("%d%c",f[i]," \n"[i==n]);
init(); //初始各个点的2^j祖先是谁
for(i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
cout<<lca(a,b)<<endl;
}
return 0;
}
/*
最近公共祖先lca,在线算法/倍增法,模板题。套别人模板自己敲了遍,现在还要回顾下邻接表,哎。。
用vector,发现爆栈了,汗一个。。
用#pragma comment(linker, "/STACK:1024000000,1024000000") 开个把栈开大点吧。。hdu可以,别的地方就不清楚了
*/
/*
1 10 7
1 2 2
1 4 4
2 3 3
2 5 6
3 7 1
3 8 2
5 6 3
6 9 2
4 10 4
*/