【题解】这题看起来就像倍增0 0 {没有为什么}
三个点要走到一起,必定是其中两个点先走到它们的lca,然后第三个点走过去。所以预处理lca后把三种情况都算出来就可以了。
#include <cstdio>
#include <iostream>
#include <cstring>
#define N 200005
struct edge{ int to,nxt;}e[N<<1];
int n,m,ans,anss,cnt,f[N][20],d[N],q[N],fi[N];
bool bo[N];
void add(int u,int v)
{
e[++cnt].to=v;e[cnt].nxt=fi[u];fi[u]=cnt;
}
void lca()
{
int h=1,t=1;
memset(bo,false,sizeof(bo));
for (bo[q[1]=1]=true;h<=t;++h)
for (int i=fi[q[h]];i;i=e[i].nxt)
if (!bo[e[i].to])
{
bo[q[++t]=e[i].to]=true;
f[e[i].to][0]=q[h];
d[e[i].to]=d[q[h]]+1;
for (int j=0,k=q[h];f[k][j];k=f[k][j++])
f[e[i].to][j+1]=f[k][j];
}
}
int findlca(int u,int v)
{
if (d[u]<d[v]) std::swap(u,v);
for (int j;d[u]>d[v];u=f[u][j-1])
for (j=1;d[f[u][j]]>d[v];++j);
for (int j;u!=v;u=f[u][j-1],v=f[v][j-1])
for (j=1;f[u][j]!=f[v][j];++j);
return u;
}
int calc(int x,int y,int z,int p,int q)
{
return d[x]+d[y]-d[z]-d[p]+d[q]-d[p];
}
int main()
{
scanf("%d%d\n",&n,&m);
for (int i=1;i<n;++i)
{
int u,v;
scanf("%d%d\n",&u,&v);
add(u,v);add(v,u);
}
lca();
for (int i=1;i<=m;++i)
{
int x,y,z;
scanf("%d%d%d\n",&x,&y,&z);
int f1=findlca(x,y),
f2=findlca(y,z),
f3=findlca(x,z);
int s1=calc(x,y,f1,findlca(f1,z),z),
s2=calc(y,z,f2,findlca(f2,x),x),
s3=calc(x,z,f3,findlca(f3,y),y);
if (s1<=s2 && s1<=s3) ans=f1,anss=s1;
if (s2<s1 && s2<s3) ans=f2,anss=s2;
if (s3<s2 && s3<s1) ans=f3,anss=s3;
printf("%d %d\n",ans,anss);
}
return 0;
}
【题外话】最近做题的时候总是有点恹恹的QAQ。。。如何防止犯困。。。