给出 n 个点的一棵树,多次询问两点之间的最短距离。
注意:
- 边是无向的。
- 所有节点的编号是 1,2,…,n。
输入格式
第一行为两个整数 n 和 m。n 表示点数,m 表示询问次数;
下来 n−1 行,每行三个整数 x,y,k,表示点 x 和点 y 之间存在一条边长度为 k;
再接下来 m 行,每行两个整数 x,y,表示询问点 x 到点 y 的最短距离。
树中结点编号从 1 到 n。
输出格式
共 m 行,对于每次询问,输出一行询问结果。
数据范围
2≤n≤10^4,
1≤m≤2×10^4,
0<k≤100,
1≤x,y≤n
输入样例1:
2 2
1 2 100
1 2
2 1
输出样例1:
100
100
输入样例2:
3 2
1 2 10
3 1 15
1 2
3 2
输出样例2:
10
25
思路
tarjan模板题
代码
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int fa[N],h[N],n,idx,st[N],ans[N*2],dep[N];
struct eg{
int v,w,nex;
}e[N*2];
int Find(int x){
return fa[x]==x? x:fa[x]=Find(fa[x]);
}
void add(int u,int v,int w){
e[idx]=(eg){v,w,h[u]};
h[u]=idx++;
}
vector<pair<int,int> > query[N];
void dfs(int u){
st[u]=1;
for(int i=h[u];~i;i=e[i].nex){
int v=e[i].v,w=e[i].w;
if(st[v]) continue;
dep[v]=dep[u]+w;
dfs(v);
fa[v]=u;
}
for(auto it: query[u]){
int v=it.first,id=it.second;
if(st[v]==2){
ans[id]=dep[u]+dep[v]-dep[Find(v)]*2;
}
}
st[u]=2;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) fa[i]=i;
memset(h,-1,sizeof h);idx=0;
for(int i=1;i<n;++i){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);
add(y,x,w);
}
for(int i=1;i<=m;++i){
int x,y;
scanf("%d%d",&x,&y);
query[x].push_back({y,i});
query[y].push_back({x,i});
}
dfs(1);
for(int i=1;i<=m;++i) cout<<ans[i]<<endl;
return 0;
}