【BZOJ1787】[Ahoi2008]Meet 紧急集合 LCA

【BZOJ1787】[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

Sample Output

5 2
2 5
4 1
6 0

HINT

题解:自己画画图就能看出来,对于询问(a,b,c),我们两两求出LCA,然后一定是选择深度最大的LCA作为集合点。就没有然后了

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=500010;
int n,m,cnt;
int to[maxn<<1],next[maxn<<1],head[maxn],fa[maxn][22],dep[maxn];
void dfs(int x)
{
	for(int i=head[x];i!=-1;i=next[i])
	{
		if(to[i]==fa[x][0])	continue;
		fa[to[i]][0]=x,dep[to[i]]=dep[x]+1,dfs(to[i]);
	}
}
void add(int a,int b)
{
	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
int lca(int a,int b)
{
	if(dep[a]<dep[b])	swap(a,b);
	int i;
	for(i=19;i>=0;i--)	if(dep[fa[a][i]]>=dep[b])	a=fa[a][i];
	if(a==b)	return a;
	for(i=19;i>=0;i--)	if(fa[a][i]!=fa[b][i])	a=fa[a][i],b=fa[b][i];
	return fa[a][0];
}
int main()
{
	scanf("%d%d",&n,&m);
	int i,j,a,b,c,x,y,z;
	memset(head,-1,sizeof(head));
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&a,&b);
		add(a,b),add(b,a);
	}
	dep[1]=1,dfs(1);
	for(j=1;(1<<j)<=n;j++)	for(i=1;i<=n;i++)	fa[i][j]=fa[fa[i][j-1]][j-1];
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		x=lca(a,b),y=lca(b,c),z=lca(a,c);
		if(dep[x]<dep[y])	swap(x,y);
		if(dep[x]<dep[z])	swap(x,z);
		if(dep[y]<dep[z])	swap(y,z);
		printf("%d %d\n",x,dep[a]+dep[b]+dep[c]-2*dep[z]-dep[x]);
	}
	return 0;
}
posted @ 2017-03-29 12:41  CQzhangyu  阅读(186)  评论(0编辑  收藏  举报