dongzhiyuan1007
2024-11-18 23:18:45
题目传送门
考虑倍增 LCA 算法。
每次询问分别求三个点中每两个点的 LCA 点,然后分别求出这三个点到此 LCA 点的距离和,并取最小值即可。
值得一提的是,某两点间的距离不一定是两者的
#include<bits/stdc++.h>
#include<queue>
using namespace std;
const int N=500010,M=1000010,INF=0x3f3f3f3f;
int n,m;
int h[N],e[M],ne[M],idx;
int depth[N],fa[N][25];
queue<int> q;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs()
{
memset(depth,0x3f,sizeof depth);
depth[0]=0,depth[1]=1;
q.push(1);
while(q.size())
{
int t=q.front();
q.pop();
for(int i=h[t];~i;i=ne[i])
{
int j=e[i];
if(depth[j]>depth[t]+1)
{
depth[j]=depth[t]+1;
q.push(j);
fa[j][0]=t;
for(int k=1;k<=18;k++)
{
fa[j][k]=fa[fa[j][k-1]][k-1];
}
}
}
}
}
int lca(int a,int b)
{
if(depth[a]<depth[b]) swap(a,b);
for(int i=18;i>=0;i--)
{
if(depth[fa[a][i]]>=depth[b]) a=fa[a][i];
}
if(a==b) return b;
for(int i=18;i>=0;i--)
{
if(fa[a][i]!=fa[b][i])
{
a=fa[a][i];
b=fa[b][i];
}
}
return fa[a][0];
}
int dist(int a,int b)
{
int t=lca(a,b);
return abs(depth[t]-depth[a])+abs(depth[t]-depth[b]);
}
int check(int x,int y,int z,int ver)
{
return dist(x,ver)+dist(y,ver)+dist(z,ver);
}
int main()
{
cin.tie(0)->sync_with_stdio(0);
cout.tie(0)->sync_with_stdio(0);
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=1;i<n;i++)
{
int a,b;
cin>>a>>b;
add(a,b),add(b,a);
}
bfs();
while(m--)
{
int x,y,z;
cin>>x>>y>>z;
int res=0,minn=INF;
int a=lca(x,y),b=lca(x,z),c=lca(y,z);
if(minn>check(x,y,z,a)) res=a,minn=check(x,y,z,a);
if(minn>check(x,y,z,b)) res=b,minn=check(x,y,z,b);
if(minn>check(x,y,z,c)) res=c,minn=check(x,y,z,c);
cout<<res<<" "<<minn<<'\n';
}
return 0;
}