题意
PS:(最近好多题题意都好难懂啊QAQ)
给你一棵 个节点的树,有
次询问,每个询问给你
三个节点,求树上一个节点使得这三个点到的距离之和最小。每次询问输出这个节点的编号以及路径之和。
分析
考虑每两个节点之间的最短距离就是求这两个点的 ,那么三个点我们可以先两两一组找到
。我们可以发现三个点的
要么是完全一样,要么是有两个(两个相同,一个不同),如果是有两种
那么此时我们要选择不同的那一个这样才能使路径最短,因为可以保证有一条路径不会重复两遍。
就比如下面这张图,如果我们的询问是 那么
的
就是
。
的
就是
。
的
就是
。此时我们的选择就是
,因为这样可以少走一次
这条边。完毕
代码
#include<bits/stdc++.h>
#define ll long long
const int N=5e5+5,INF=0x3f3f3f3f,mod=998244353;
using namespace std;
int n,m,cnt;
int head[N],dep[N],fa[N][20],lg[N];
struct node
{
int nxt,to;
}e[N<<1];
inline int read()
{
register int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
int qpow(int a,int b)
{
int ans=1;
while(b){if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}
return ans;
}
void add(int u,int v)
{
e[++cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void dfs(int x,int fath)
{
dep[x]=dep[fath]+1;
fa[x][0]=fath;
for(int i=1;i<=lg[dep[x]];i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fath)
dfs(e[i].to,x);
}
int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
while(dep[x]>dep[y]) x=fa[x][lg[dep[x]-dep[y]]-1];
if(x==y) return x;
for(int i=lg[dep[x]];i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
for(int i=1;i<n;i++)
{
int u=read(),v=read();
add(u,v);add(v,u);
}
dfs(1,0);
for(int i=1;i<=m;i++)
{
int x=read(),y=read(),z=read();
int t1=LCA(x,y),t2=LCA(y,z),t3=LCA(x,z);
int t;
if(t1==t2) t=t3;
else if(t1==t3) t=t2;
else if(t2==t3) t=t1;
ll ans=dep[x]+dep[y]+dep[z]-dep[t1]-dep[t2]-dep[t3];
printf("%d %lld\n",t,ans);
}
return 0;
}

京公网安备 11010502036488号