樹剖+LCA--bzoj1787: [Ahoi2008]Meet 緊急集合
阿新 • • 發佈:2018-12-14
傳送門 這個集結點一定是在三個點到LCA的路徑上,而且在任意兩點的LCA中的某一個上,所以就把三個LCA算出來都算一下花費的錢數取最小的
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 500005
using namespace std;
int n,m,cnt,head[N],ans,p;
int tot,dfn[N],dep[N], rk[N],fa[N],siz[N],top[N],son[N];
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
inline int max(int x,int y){return x>y?x:y;}
struct EDGE{
int to,nxt;
}edge[N<<1] ;
inline void add(int x,int y){
edge[++cnt].to=y; edge[cnt].nxt=head[x]; head[x]=cnt;
}
inline void dfs1(int u,int fat,int depth){
dep[u]=depth,fa[u]=fat,siz[u]=1;
int maxson=-1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to; if(v==fat) continue;
dfs1(v,u,depth+1); siz[u]+=siz[v];
if (siz[v]>maxson) son[u]=v,maxson=siz[v];
} return;
}
inline void dfs2(int u,int topf){
dfn[u]=++tot; rk[tot]=u; top[u]=topf;
if(!son[u]) return;
dfs2(son[u],topf);
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(!dfn[v]) dfs2(v,v);
}
}
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]?x:y;
}
int main(){
n=rd(); m=rd();
for(int i=1;i<n;i++){
int x=rd(),y=rd();
add(x,y); add(y,x);
}
dfs1(1,0,1); dfs2(1,1);
for(int i=1;i<=m;i++){
int x=rd(),y=rd(),z=rd();
int a=LCA(x,y),b=LCA(y,z),c=LCA(x,z),d=LCA(a,b);
int tmp=dep[x]+dep[y]+dep[z];
if(dep[a]>=dep[b] && dep[a]>=dep[c])
ans=tmp-dep[a]-2*dep[d],p=a;
else if(dep[b]>=dep[a] && dep[b]>=dep[c])
ans=tmp-dep[b]-2*dep[d],p=b;
else ans=tmp-dep[c]-2*dep[d],p=c;
printf("%d %d\n",p,ans);
}
return 0;
}