题意:
给定一些点和连通它们的边,三个人在站在不同的点上,要集合到同一点上去,问最小的总步数
题解:
①一个关于LCA的题
②记住一个结论:三个点的最小距离点等于两两的LCA中与其他两个LCA不同的LCA
③然后就没了
#pragma GCC optimize (2) #include <cstdio> #include <cstring> #include <algorithm> #define maxn 500010 #define abs(x) ((x)>0?(x):-(x)) using namespace std; struct Edge{ int to,next; }a[maxn<<1]; int n,m; int head[maxn],cnt; int deep[maxn],prt[maxn],size[maxn],son[maxn]; int Time,Dfn[maxn],pos[maxn],top[maxn]; void Init(); void Insert(int,int); void DFS1(int,int,int); void DFS2(int,int); int LCA(int,int); void Solve(int,int,int); int Dis(int,int); signed main(){ // freopen("in.cpp","r",stdin); Init(); return 0; } void Init(){ scanf("%d%d",&n,&m); int x,y,z; for(int i=1;i<n;i++){ scanf("%d%d",&x,&y); Insert(x,y);Insert(y,x); } DFS1(1,0,1); DFS2(1,1); while(m--){ scanf("%d%d%d",&x,&y,&z); Solve(x,y,z); } } void Solve(int x,int y,int z){ int a=LCA(x,y),b=LCA(x,z),c=LCA(y,z); int prt; if(a==b)prt=c; else if(a==c)prt=b; else prt=a; printf("%d %d\n",prt,Dis(x,prt)+Dis(y,prt)+Dis(z,prt)); } int Dis(int x,int y){ int prt=LCA(x,y); return deep[x]+deep[y]-2*deep[prt]; } void Insert(int x,int y){ a[++cnt].to=y; a[cnt].next=head[x]; head[x]=cnt; } void DFS1(int x,int prt,int deep){ ::deep[x]=deep; ::prt[x]=prt; ::size[x]=1; for(int i=head[x];i;i=a[i].next){ int y=a[i].to; if(y==prt)continue; DFS1(y,x,deep+1); size[x]+=size[y]; if(size[y]>size[son[x]])son[x]=y; } } void DFS2(int x,int top){ ::Dfn[x]=++Time; ::top[x]=top; ::pos[Time]=x; if(son[x])DFS2(son[x],top); for(int i=head[x];i;i=a[i].next){ int y=a[i].to; if(y==prt[x]||y==son[x])continue; DFS2(y,y); } } int LCA(int x,int y){ while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]])std::swap(x,y); x=prt[top[x]]; } if(deep[x]<deep[y])return x; return y; }