bzoj 1787: [Ahoi2008]Meet 紧急集合
1787: [Ahoi2008]Meet 紧急集合
Description
Input
Output
Sample Input
6 4
1 2
2 3
2 4
4 5
5 6
4 5 6
6 3 1
2 4 4
6 6 6
1 2
2 3
2 4
4 5
5 6
4 5 6
6 3 1
2 4 4
6 6 6
Sample Output
5 2
2 5
4 1
6 0
2 5
4 1
6 0
HINT
题解:
n-1条边,很明显这是一棵树
那么题目就是求3个点的LCA
我们将3个点x,y,z分别求出x,y的LCA,设为a,x,z的为b,y,z的为c
则a,b,c 3个点中必有两个相等,答案就是另外一个(自已画画图就知道了)
那么再求3个点到它的距离就OK了。
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; int n,m,i,j,x,y,z,a,b,c,t,p[500005],r[500005],f[500005][21]; int tot,head[500005],Next[1000005],to[1000005]; void add(int x,int y) { tot++; to[tot]=y; Next[tot]=head[x]; head[x]=tot; } void dfs(int x) { int i; for(i=head[x];i!=-1;i=Next[i]) if(p[to[i]]==0) { p[to[i]]=1; r[to[i]]=r[x]+1; f[to[i]][0]=x; dfs(to[i]); } } int LCA(int a,int b) { int i; if(r[a]<r[b]) swap(a,b); for(i=20;i>=0;i--) if(f[a][i]&&r[f[a][i]]>=r[b]) a=f[a][i]; if(a==b) return a; for(i=20;i>=0;i--) if(f[a][i]&&f[b][i]&&f[a][i]!=f[b][i]) { a=f[a][i]; b=f[b][i]; } return f[a][0]; } int dis(int x,int y) { int a=LCA(x,y); return r[x]+r[y]-2*r[a]; } int main() { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) head[i]=-1; for(i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } p[1]=1; r[1]=1; dfs(1); for(j=1;j<=20;j++) for(i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; for(i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); a=LCA(x,y); b=LCA(x,z); c=LCA(y,z); if(a==b) t=c;else if(b==c) t=a;else t=b; printf("%d %d\n",t,dis(x,t)+dis(y,t)+dis(z,t)); } return 0; }
一念起,天涯咫尺; 一念灭,咫尺天涯。