题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1787
题解:
求出三个点两两之间的lca会发现有两个是一样的,然后我们选那个不一样的就好了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std; struct use{ int st,en; }b[5000001]; int cnt,u,v,point[500001],next[5000001],deep[500001],fa[500001][20],n,m,x,y,z,aa,bb,cc,vis[1000001]; void add(int x,int y) { ++cnt;next[cnt]=point[x];point[x]=cnt; b[cnt].st=x;b[cnt].en=y; } void dfs(int x) { vis[x]=1; for (int i=1;i<=15;i++) { if ((1<<i)>deep[x]) break; fa[x][i]=fa[fa[x][i-1]][i-1]; } for (int i=point[x];i;i=next[i]) { if (vis[b[i].en]) continue; deep[b[i].en]=deep[x]+1; fa[b[i].en][0]=x; dfs(b[i].en); } } int lca(int x,int y) { int t; if (deep[x]<deep[y]) swap(x,y); t=deep[x]-deep[y]; for (int i=0;i<=15;i++) if ((1<<i)&t) x=fa[x][i]; for (int i=15;i>=0;i--) if (fa[x][i]!=fa[y][i]) { x=fa[x][i]; y=fa[y][i]; } if (x==y) return x; else return fa[x][0]; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n-1;i++) { scanf("%d%d",&u,&v); add(u,v);add(v,u); } for (int i=0;i<=15;i++) fa[1][i]=1; dfs(1); for (int i=1;i<=m;i++) { int tt,zu; scanf("%d%d%d",&x,&y,&z); aa=lca(x,y);bb=lca(x,z);cc=lca(y,z); if (aa==bb) zu=cc;if (aa==cc) zu=bb;if (bb==cc) zu=aa; aa=lca(zu,x);bb=lca(zu,y);cc=lca(zu,z); tt=-(deep[aa]-deep[zu])-(deep[aa]-deep[x])-(deep[bb]-deep[zu])-(deep[bb]-deep[y])-(deep[cc]-deep[zu])-(deep[cc]-deep[z]); printf("%d %d\n",zu,tt); } }
时间: 2024-10-09 09:17:45