LUOGU P4281 [AHOI2008]紧急集合 / 聚会 (lca)
解题思路
可以通过手玩或打表发现,其实要选的点一定是他们三个两两配对后其中一对的$lca$上,那么就直接算出来所有的$lca$,比较大小就行了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; const int MAXN = 500005; inline int rd(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } int ans,p,n,m,head[MAXN],cnt,num; int to[MAXN<<1],nxt[MAXN<<1]; int id[MAXN],dep[MAXN],top[MAXN],fa[MAXN],siz[MAXN],son[MAXN]; inline void add(int bg,int ed){ to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt; } void dfs1(int x,int f,int d){ dep[x]=d,fa[x]=f,siz[x]=1;register int maxson=0,u; for(register int i=head[x];i;i=nxt[i]){ u=to[i];if(u==f) continue; dfs1(u,x,d+1);siz[x]+=siz[u]; if(siz[u]>maxson) {maxson=u;son[x]=u;} } } void dfs2(int x,int topf){ top[x]=topf;id[x]=++num;if(!son[x]) return;dfs2(son[x],topf);int u; for(register int i=head[x];i;i=nxt[i]){ u=to[i];if(u==fa[x] || u==son[x]) continue;dfs2(u,u); } } inline int lca(int x,int y){ while(top[x]!=top[y]){ if(dep[top[x]]>dep[top[y]]) x=fa[top[x]]; else y=fa[top[y]]; } return dep[x]>dep[y]?y:x; } inline void LCA(int x,int y,int z){ register int tmp,dis,all;tmp=lca(x,y);all=lca(tmp,z); dis=dep[x]+dep[y]-dep[tmp]+dep[z]-2*dep[all];ans=dis;p=tmp;dis+=dep[tmp]; tmp=lca(x,z);dis-=dep[tmp];if(ans>dis) {ans=dis;p=tmp;} dis+=dep[tmp];tmp=lca(y,z);dis-=dep[tmp];if(ans>dis) {ans=dis;p=tmp;} } void out(int x){ if(!x) return; out(x/10);putchar('0'+x%10); } int main(){ n=rd(),m=rd();int x,y,z; for(register int i=1;i<n;i++){ x=rd(),y=rd();add(x,y),add(y,x); } dfs1(1,0,1),dfs2(1,1); while(m--) { x=rd(),y=rd(),z=rd();ans=1e9; LCA(x,y,z);out(p);putchar(' ');if(!ans) putchar('0');else out(ans); putchar('\n'); } return 0; }