【旅行】

来源:互联网 发布:芒果tv mac客户端 编辑:程序博客网 时间:2024/04/27 17:24

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);    }  }  }  }


0 0
原创粉丝点击