这道题莫名眼熟,于是马上猜到了结论:

对于一棵树中,要求到三个点x,y,z总距离最小的点,那么,这个点一定是

lca(x,y),lca(x,z),lca(y,z)这三个点中的一个(一开始我还算了lca(x,y,z),后来发现好像不用。。。)

所以,我们可以打个lca,每次再比较下到哪个点距离最小即可~

update:补一下结论的证明

我们将情况分为以下三种:

1.

画个图不难发现,若我们将A上移一下,那么,距离和会+3。

若我们下移,分两种情况:

①向有x/y/z的儿子下移,距离和+2
②向没有x/y/z的儿子下移,距离和+3

所以距离和最小的点就是A

2.

不难证明,若要满足此情况,则A一定为B的真祖先

同样,我们分三种情况:

①B向上移动则,距离和+2-1(y,z距离+1,x距离-1)
②B向有y/z的儿子下移,距离和+2-1(y/z距离-1,z/y,x距离+1)
③B向没有y/z的儿子下移,距离和+3

所以距离和最小的就是B

由于x,y,z具有对称性,所以其他同理

3.

不难证明,不存在这种情况,证明如下:

若z不在A的子树里面,则

若z在A的子树里面,则:
①x和z在A的同一个儿子子树里面,可以转化为:,y不在B的子树,所以有
y和z在A的同一个儿子子树同理
②z和x和y都不在不在A的同一个儿子子树里面,则一定有:

命题得证。

所以综上所述,答案一定是三个点两两lca的点中的一个

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+1;
struct node{
    int v,nex;
}t[N<<1];
int las[N],len;
inline void add(int u,int v){
    t[++len]=(node){v,las[u]},las[u]=len;
}
int fa[N][19],dep[N];
inline void dfs(int now,int fu){
    fa[now][0]=fu;
    for(int i=1;i<=18;++i){
        fa[now][i]=fa[fa[now][i-1]][i-1];
        if(!fa[now][i]){
            break;
        }
    }
    for(int i=las[now];i;i=t[i].nex){
        int v=t[i].v;
        if(v!=fu){
            dep[v]=dep[now]+1;
            dfs(v,now);
        }
    }
}
inline int lca(int x,int y){
    if(dep[x]<dep[y]){
        x^=y^=x^=y;
    }
    int cha=dep[x]-dep[y];
    for(int i=18;~i;--i){
        if(cha>=(1<<i)){
            cha-=(1<<i);
            x=fa[x][i];
        }
    }
    if(x==y){
        return x;
    }
    for(int i=18;~i;--i){
        if(fa[x][i]!=fa[y][i]){
            x=fa[x][i],y=fa[y][i];
        }
    }
    return fa[x][0];
}
inline int dis(int x,int y){
    int z=lca(x,y);
    return dep[x]+dep[y]-2*dep[z];
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;++i){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    dep[1]=1;
    dfs(1,0);
    while(m--){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        int res=2e9,gol=0,now=0,fow=0;
        now=lca(x,y);fow=dis(x,now)+dis(y,now)+dis(z,now);
        if(res>fow){
            res=fow;gol=now;
        }
        now=lca(x,z);fow=dis(x,now)+dis(y,now)+dis(z,now);
        if(res>fow){
            res=fow;gol=now;
        }
        now=lca(y,z);fow=dis(x,now)+dis(y,now)+dis(z,now);
        if(res>fow){
            res=fow;gol=now;
        }
        now=lca(x,lca(y,z));fow=dis(x,now)+dis(y,now)+dis(z,now);
        if(res>fow){
            res=fow;gol=now;
        }
        printf("%d %d\n",gol,res);
    }
    return 0;
}