Description
【题解】
一道lca水题
随便画画图就可以看出ABC之间的关系只有三种
1.三个节点有共同的共祖先
2.两个节点的公共祖先与另一个节点的公共祖先相同,且这个公共祖先是那两个节点公共祖先的祖先
3.两个节点的公共祖先与另一个节点的公共祖先相同,且这个这两个节点的公共祖先时两个节点其中一个(一条链的情况)
图比较丑随便看看
因此我们只需要对于三个点两两找lca 然后判断出是那种情况
剩下的就比较简单了 参照代码查看集合点和距离的做法
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <stack>
#include <vector>
#include <queue>
#include <map>
using namespace std;
int i,j,k,l,m,n,x,y,z,fa,fb,fc,q,num;
int f[200005][22],d[200005],first[200005];
struct info
{
int ar,next;
}tree[400005];
void add(int x,int y) {tree[++num]={y,first[x]};first[x]=num;}
void dfs(int u,int fat)
{
int i,v;
for (i=first[u];i;i=tree[i].next)
{
v=tree[i].ar;
if (v==fat) continue;
d[v]=d[u]+1;f[v][0]=u;
dfs(v,u);
}
}
int lca(int u,int v)
{
int i;
if (d[v]>d[u]) swap(u,v);
for (;d[u]>d[v];)
{
for (i=0;d[f[u][i]]>=d[v];i++);i--;
u=f[u][i];
}
for (;u!=v;)
{
for (i=1;f[u][i]!=f[v][i];i++);i--;
u=f[u][i];v=f[v][i];
}
return(u);
}
int main()
{
scanf("%d%d",&n,&m);
for (i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
f[1][0]=1;d[1]=1;
dfs(1,-1);
for (i=1;i<=20;i++)
for (j=1;j<=n;j++)
f[j][i]=f[f[j][i-1]][i-1];
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
fa=lca(x,y);fb=lca(y,z);fc=lca(x,z);
if (fa==fb&&fb==fc)
{
q=d[x]+d[y]+d[z]-3*d[fa];
printf("%d %d\n",fa,q);
continue;
}
if (fa==fc) {swap(x,y);}
if (fb==fc) {swap(y,z);}
fa=lca(x,y);fb=lca(y,z);fc=lca(x,z);
if (fa==fb)
{
if (fc==z||fc==x)
{
if (fc==z){q=d[x]+d[y]-2*d[fa];printf("%d %d\n",z,q);continue;}
if (fc==x){q=d[z]+d[y]-2*d[fa];printf("%d %d\n",x,q);continue;}
continue;
}
else
{
q=d[x]+d[z]-2*d[fc]+d[fc]+d[y]-2*d[lca(fc,y)];
printf("%d %d\n",fc,q);
}
}
}
}