1. 程式人生 > >樹剖+LCA--bzoj1787: [Ahoi2008]Meet 緊急集合

樹剖+LCA--bzoj1787: [Ahoi2008]Meet 緊急集合

傳送門 solution:solution: 這個集結點一定是在三個點到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; }