【bzoj1832】 AHOI2008聚会 lca

不错的题,就是找lca呗。

因为三个点,所以一定在三个点连接的树枝上,那么先两个求个lca,第三个再走到这里就可以了。


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 500010

using namespace std;

int next[2*maxn],to[2*maxn],head[maxn],dep[maxn],fa[maxn][21];
int n,m,num,T;

void addedge(int x,int y)
{
	num++;to[num]=y;next[num]=head[x];head[x]=num;
}

void dfs(int x)
{
	for (int p=head[x];p;p=next[p])
	  if (to[p]!=fa[x][0])
	  {
	  	fa[to[p]][0]=x;
	  	dep[to[p]]=dep[x]+1;
	  	dfs(to[p]);
	  }
}

int go_up(int x,int d)
{
	for (int i=0;i<=20;i++)
	  if (d&(1<<i)) x=fa[x][i];
	return x;
}

int LCA(int x,int y)
{
	if (dep[x]>dep[y]) x=go_up(x,dep[x]-dep[y]);
	else y=go_up(y,dep[y]-dep[x]);
	if (x==y) return x;
	for (int i=20;i>=0;i--)
	  if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}

int main()
{
	scanf("%d%d",&n,&T);
	for (int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		addedge(x,y);addedge(y,x);
	}
	dep[1]=0;fa[1][0]=0;
	dfs(1);
	for (int j=1;j<=20;j++)
	  for (int i=1;i<=n;i++)
	    if (fa[i][j-1]) fa[i][j]=fa[fa[i][j-1]][j-1];
	    else fa[i][j]=0;
	while (T--)
	{
		int a,b,c,ans,id,lca1,lca2,sum;
		scanf("%d%d%d",&a,&b,&c);
		lca1=LCA(a,b);sum=dep[a]-dep[lca1]+dep[b]-dep[lca1];
		lca2=LCA(lca1,c);sum+=dep[lca1]-dep[lca2]+dep[c]-dep[lca2];
		ans=sum,id=lca1;
		lca1=LCA(b,c);sum=dep[b]-dep[lca1]+dep[c]-dep[lca1];
		lca2=LCA(lca1,a);sum+=dep[lca1]-dep[lca2]+dep[a]-dep[lca2];
		if (sum<ans) ans=sum,id=lca1;
		lca1=LCA(a,c);sum=dep[a]-dep[lca1]+dep[c]-dep[lca1];
		lca2=LCA(lca1,b);sum+=dep[lca1]-dep[lca2]+dep[b]-dep[lca2];
		if (sum<ans) ans=sum,id=lca1;
		printf("%d %d\n",id,ans);
	}
	return 0;
}


你可能感兴趣的:(【bzoj1832】 AHOI2008聚会 lca)