How far away ?
题 意:给你一个有n个节点的树,树的边有权值k,问数上两个节点s,t的最短距离。
数据范围:
2<=n<=2e4
1<=m<=2e2
0<=k<=4e3
输入样例:
2
3 2
1 2 10
3 1 15
1 2
2 3
输出样例:
2 2
1 2 100
1 2
2 1
思 路:因为给出的是一颗树,但是没有确定根节点,所以先要dfs建树。建树的过程中顺便处理一下,每个节点的父节点,以及每个节点到根节点的距离。
收 获:对LCA的理解更加深刻,理解了更加lca的姿势
#include<bits/stdc++.h>
#define mst(x,y) memset(x,y,sizeof(x));
using namespace std;
const int maxn = 4e4+5;
int father[maxn][20]; //开始是数组开小了
struct node{
int to,value;
node(int a=0,int b=0){to = a;value=b;}
};
vector<node> edge[maxn];
int f[maxn],depth[maxn];
int bin[17];
int dis[maxn];
bool vis[maxn];
int n,q;
void make_bin(){
bin[0] = 1;
for(int i=1;i<=16;i++){
bin[i] = bin[i-1] <<1;
}
}
void dfs(int u,int pre,int dep){
f[u] = pre;
depth[u] = dep;
for(int i=0;i<edge[u].size();i++){
int v = edge[u][i].to;
if(v!=pre){
dis[v] = dis[u] + edge[u][i].value;
dfs(v,u,dep+1);
}
}
}
void init(){
for(int i=1;i<=n;i++) father[i][0] = f[i];
for(int j=1;(1<<j)<=n;j++){
for(int i=1;i<=n;i++){
if(father[i][j-1]!=0){
father[i][j] = father[father[i][j-1]][j-1];
}
}
}
}
int lca(int x,int y){
if(depth[x] < depth[y]) swap(x,y);
int t = depth[x] - depth[y];
for(int i=0;i<=16;i++){
if(t&bin[i])x = father[x][i];
}
for(int i=16;i>=0;i--){
if(father[x][i]^father[y][i]){
x = father[x][i];y = father[y][i];
}
}
if(!(x^y)) return y;
else return father[x][0];
}
void init1(){
for(int i=0;i<maxn;i++)edge[i].clear();
mst(f,0);
mst(depth,0);
mst(dis,0);
mst(vis,false);
mst(father,0);
}
int main(){
make_bin();
int t;
scanf("%d",&t);
while(t--){
init1();
scanf("%d %d",&n,&q);
for(int i=1;i<n;i++){
int u,v,cos;
scanf("%d %d %d",&u,&v,&cos);
edge[u].push_back(node{v,cos});
edge[v].push_back(node{u,cos});
}
dis[1] = 0;
dfs(1,0,0);
init();
for(int i=0;i<q;i++){
int s,t;
scanf("%d %d",&s,&t);
printf("%d\n",dis[s]+dis[t]-2*dis[lca(s,t)]);
}
}
return 0;
}