问题描述
何老板最近在玩一款追铺游戏,游戏虽然简单,何老板仍旧乐此不疲。
游戏地图中有n座城市由n-1条双向道路连接。任意两座城市都可相互到达。一名罪犯从A城市出发沿最短路线逃往B城市。在罪犯出发的同时,何老板控制一名警察从C城市出发去追捕那名罪犯。每条道路都有一定的长度(单位米)。罪犯和警察行走的速度相同,都是1秒钟行走1米。
若罪犯到达B城市时还没有被抓住,何老板就输掉了这局游戏。何老板总共玩了m局游戏,每局游戏开始前,何老板想知道他是否能赢下这局游戏,如果能,警察最少行走多少米才能抓到罪犯?
输入格式
第一行,两个整数n和m
接下来n-1行,每行三个整数X,Y,Z,表示城市X和Y之间有一条长度为Z的道路相连。
接下来m行,每行三个整数A,B,C。
输出格式
m行,每行对应一局游戏的结果。若能抓捕到罪犯。输出一个整数,表示警察最少需要行走的距离。若无法抓到罪犯,输出-1。
样例输入
11 2
1 2 6
1 3 3
1 4 3
3 5 2
3 6 5
4 7 9
6 10 3
5 8 4
5 9 3
8 11 8
11 9 10
2 4 7
样例输出
10
9
提示
【样例解释】
第1局在5号城市抓住罪犯。
第2局在4号城市抓住罪犯。
【数据范围】
对于约40% 的数据:1<=N,M<=2000
对于约100% 的数据:1<=N,M<=100000 1<=道路的长度<=10000
题解
树上两点有且仅有一条路径到达,所以两者到同一节点必定会在一点汇合,此点最坏情况为到此节点。
注意lca两点向上跳时最小可为0
代码
#include<stdio.h>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
#define inf 1e9
#define pr cout<<
#define maxn 200005
int cnt;
int Last[maxn],Next[maxn],Len[maxn],End[maxn];
int f[maxn][20],dis[maxn][20];
int n,m;
int ans;
int dep[maxn];
void insert(int a,int b,int c)
{
Next[++cnt]=Last[a];
Last[a]=cnt;
End[cnt]=b;
Len[cnt]=c;
}
void dfs(int x){
int i,j;
dep[x]=dep[f[x][0]]+1;
int k=ceil(log2(dep[x]));
for(i=1;i<=k;i++){
f[x][i]=f[f[x][i-1]][i-1];
dis[x][i]=dis[x][i-1]+dis[f[x][i-1]][i-1];
}
for(i=Last[x];i;i=Next[i]){
int en=End[i];
if(en!=f[x][0]){
f[en][0]=x;
dis[en][0]=Len[i];
dfs(en);
}
}
}
int lca(int a,int b)
{
int i,s,j,k;
ans=0;
k=ceil(log2(n));
if(dep[a]<dep[b]) swap(a,b);
s=dep[a]-dep[b];
for(i=0;i<=k;i++){
if(s&(1<<i)){
ans+=dis[a][i];
a=f[a][i];
}
}
if(b==a) return a;
s=ceil(log2(n));
for(i=s;i>=0;i--){
if(f[a][i]!=f[b][i]){
ans+=dis[a][i];ans+=dis[b][i];
a=f[a][i];b=f[b][i];
}
}
ans+=dis[a][0];ans+=dis[b][0];
return f[a][0];
}
int main()
{
int i,j;
scanf("%d%d",&n,&m);
int x,y,z;
for(i=1;i<=n-1;i++){
scanf("%d%d%d",&x,&y,&z);
insert(x,y,z);
insert(y,x,z);
}
dfs(1);
int l1,l2,l3;
int a1,a2,a3;
int s1,s2,t;
for(i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
l1=lca(x,y);
l2=lca(y,z);
l3=lca(x,z);
if(l1==l2){
s1=lca(l3,x);s1=ans;
s2=lca(l3,z);s2=ans;
}
else if(l1==l3){
s1=lca(l2,x);s1=ans;
s2=lca(l2,z);s2=ans;
}
else if(l2==l3){
s1=lca(l1,x);s1=ans;
s2=lca(l1,z);s2=ans;
}
if(s1<s2) cout<<"-1"<<endl;
else cout<<s2<<endl;
}
}