问题描述
何老板最近在玩一款追铺游戏,游戏虽然简单,何老板仍旧乐此不疲。
游戏地图中有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
在小偷从a到b的过程中,必然在路径上有且仅有一点T,使T与b相连,否则构成环。
如果找到这个T点,若警察在小偷之前或者恰好到达T,则可以抓到。
那么,如何找到T点?
如图,我们显然可以得到这个结论:
a,b,c三点两两LCA,则T点为其中不同的那个最近公共祖先。
另外,还需要注意边带权即可。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
using namespace std;
const int need=100060;
const double lg2=log(2);
int n,m,i,j;
int las[need],nex[need],en[need],len[need];
int dep[need],fa[need][22],dis[need];
int tot=0,d=0;
inline void re(int &d)
{
bool f=false;char t=getchar();
while(t<'0'||t>'9'){if(t=='-')f=true;t=getchar();}
for(d=0;t>='0'&&t<='9';t=getchar())d=(d<<1)+(d<<3)+t-'0';
d=(f?(-d):(d));
}
void add(int a,int b,int c)
{
tot++;
nex[tot]=las[a];
en[tot]=b;
len[tot]=c;
las[a]=tot;
}
bool vis[need];
void dfs(int s)
{
int y;
int k=ceil(log(dep[s])/lg2);
d=max(d,k);
for(int i=1;i<=k;i++) fa[s][i]=fa[fa[s][i-1]][i-1];
for(int t=las[s];t;t=nex[t])
{
y=en[t];
if(vis[y]) continue;
vis[y]=true;
dep[y]=dep[s]+1;
dis[y]=dis[s]+len[t];
fa[y][0]=s;
dfs(y);
}
}
int lca(int v,int u)
{
if(dep[u]>dep[v]) swap(u,v);
int p=dep[v]-dep[u];
for(int i=0;i<=d;i++) if((p>>i)&1) v=fa[v][i];
if(u==v) return v;
for(int i=d;i>=0;i--) if(fa[u][i]!=fa[v][i]) v=fa[v][i],u=fa[u][i];
return fa[u][0];
}
int getdis(int a,int b)
{
int c=lca(a,b);
return dis[a]-dis[c]+dis[b]-dis[c];
}
int main()
{
//freopen("catch.in","r",stdin);
//freopen("catch.out","w",stdout);
int a,b,c,e,f[3],flag=0;
re(n);re(m);
for(i=1;i<n;i++)
{
re(a);re(b);re(c);
add(a,b,c),add(b,a,c);
}
dfs(1);
for(i=1;i<=m;i++)
{
re(a);re(b);re(c);
f[0]=lca(a,b);
f[1]=lca(b,c);
f[2]=lca(a,c);
if(f[0]==f[1])e=f[2];
else if(f[0]==f[2])e=f[1];
else if(f[1]==f[2])e=f[0];
int x=getdis(e,a),y=getdis(e,c);
if(x>=y)printf("%d\n",y);
else printf("-1\n");
}
}