【题目大意】
一个图有n个点n-1条边(也就是说是一棵树),求其中三点共同到达某一点经过总共的最少边数以及共同到达的那一点。
【思路】
借用一下黄学长给的结论:三个点两两取LCA,其中必有两个相同,则另外一个点就是答案。
注意BZOJ大数据要用scanf和printf,因为cout的原因RE了好几次_(:зゝ∠)_基本算是一道标程类的题目了啦。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 const int MAXN=500001; 9 const int M=20; 10 using namespace std; 11 int n,m; 12 vector<int> G[MAXN]; 13 int fa[MAXN][M]; 14 int dep[MAXN]; 15 16 void dfs(int v,int p,int d) 17 { 18 fa[v][0]=p; 19 dep[v]=d; 20 for (int i=0;i<G[v].size();i++) 21 if (G[v][i]!=p) dfs(G[v][i],v,d+1); 22 } 23 24 void kb() 25 { 26 for (int i=1;i<M;i++) 27 for (int j=1;j<=n;j++) 28 { 29 fa[j][i]=fa[fa[j][i-1]][i-1]; 30 } 31 } 32 33 void init() 34 { 35 scanf("%d%d",&n,&m); 36 for (int i=0;i<n-1;i++) 37 { 38 int fr,to; 39 scanf("%d%d",&fr,&to); 40 G[fr].push_back(to); 41 G[to].push_back(fr); 42 } 43 dfs(1,0,0); 44 kb(); 45 } 46 47 int swim(int x,int H) 48 { 49 for (int i=0;H>0;i++) 50 { 51 if (H&1) x=fa[x][i]; 52 H/=2; 53 } 54 return x; 55 } 56 57 int LCA(int u,int v) 58 { 59 if (dep[u]<dep[v]) swap(u,v); 60 u=swim(u,dep[u]-dep[v]); 61 if (u==v) return u; 62 for (int i=M-1;i>=0;i--) 63 { 64 if (fa[u][i]!=fa[v][i]) 65 { 66 u=fa[u][i]; 67 v=fa[v][i]; 68 } 69 } 70 return fa[u][0]; 71 } 72 73 int dis(int x,int y) 74 { 75 int z=LCA(x,y); 76 int re=dep[x]+dep[y]-2*dep[z]; 77 return re; 78 } 79 80 void query() 81 { 82 int u,v,w; 83 for (int i=0;i<m;i++) 84 { 85 scanf("%d%d%d",&u,&v,&w); 86 int uv=LCA(u,v); 87 int uw=LCA(u,w); 88 int vw=LCA(v,w); 89 int pos; 90 if (uv==uw) pos=vw; 91 else if (uv==vw) pos=uw; 92 else pos=uv; 93 int cost=dis(u,pos)+dis(v,pos)+dis(w,pos); 94 printf("%d %d\n",pos,cost); 95 } 96 } 97 98 int main() 99 { 100 init(); 101 query(); 102 return 0; 103 }