Description
给出一棵树,每次询问到某三个点x,y,z距离和最小的点是哪个和最小距离。
n,m<=5*10^5,边权为1
Solution
如果只有两个点,那么答案是什么?
很显然是lca(x,y)!
那么三个点呢?
我们可以发现,对于lca(x,y),lca(x,z),lca(y,z)这三个点,必然有两个点是相同的。
那么对于剩下一个点到那个相同的点的路径上,很明显越靠近单独的那个点答案越小。
于是求出lca判断一下就好了。
不过这道题tarjan似乎很麻烦,还是倍增好了。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=last[a];i;i=next[i])
#define N 500005
using namespace std;
int last[N],la[N],next[N*2],t[N*2];
int n,q,x,y,z,l,d[N],f[N][19];
bool bz[N];
void add(int x,int y) {
t[++l]=y;next[l]=last[x];last[x]=l;
}
void dfs(int x) {
fo(j,1,18) f[x][j]=f[f[x][j-1]][j-1];
rep(i,x) if (t[i]!=f[x][0]) {
f[t[i]][0]=x;
d[t[i]]=d[x]+1;
dfs(t[i]);
}
}
int lca(int x,int y) {
if (d[x]<d[y]) swap(x,y);
fd(j,18,0) if (d[f[x][j]]>d[y]) x=f[x][j];
if (d[x]!=d[y]) x=f[x][0];
fd(j,18,0) if (f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
if (x!=y) return f[x][0];else return x;
}
int main() {
scanf("%d%d",&n,&q);
fo(i,1,n-1) scanf("%d%d",&x,&y),
add(x,y),add(y,x);
d[1]=1;dfs(1);
for(;q;q--) {
scanf("%d%d%d",&x,&y,&z);int len=d[x]+d[y]+d[z];
int a=lca(x,y),b=lca(x,z),c=lca(y,z);
if (a==b) {int u=lca(c,x);printf("%d %d\n",c,len-d[c]-2*d[u]);}
else if (a==c) {int u=lca(b,y);printf("%d %d\n",b,len-d[b]-2*d[u]);}
else {int u=lca(a,z);printf("%d %d\n",a,len-d[a]-2*d[u]);}
}
}