BZOJ 1787: [Ahoi2008]Meet 紧急集合

题目描述

欢乐岛上有个非常好玩的游戏,叫做“紧急集合”。在岛上分散有N个等待点,有N-1条道路连接着它们,每一条道路都连接某两个等待点,且通过这些道路可以走遍所有的等待点,通过道路从一个点到另一个点要花费一个游戏币。

参加游戏的人三人一组,开始的时候,所有人员均任意分散在各个等待点上(每个点同时允许多个人等待),每个人均带有足够多的游戏币(用于支付使用道路的花费)、地图(标明等待点之间道路连接的情况)以及对话机(用于和同组的成员联系)。当集合号吹响后,每组成员之间迅速联系,了解到自己组所有成员所在的等待点后,迅速在N个等待点中确定一个集结点,组内所有成员将在该集合点集合,集合所用花费最少的组将是游戏的赢家。

小可可和他的朋友邀请你一起参加这个游戏,由你来选择集合点,聪明的你能够完成这个任务,帮助小可可赢得游戏吗?

 题解:手画一下,选择三个点两两组成 LCA 中深度最大的即可. 

#include<bits/stdc++.h>
#define maxn 600000 
using namespace std; 
void setIO(string s)
{
	string in=s+".in"; 
	freopen(in.c_str(),"r",stdin); 
}
int edges,n,Q; 
int hd[maxn],to[maxn<<1],nex[maxn<<1],dep[maxn],siz[maxn],hson[maxn],fa[maxn],top[maxn];  
void add(int u,int v)
{
	nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; 
}
void dfs1(int u,int ff)
{
	fa[u]=ff,dep[u]=dep[ff]+1,siz[u]=1; 
	for(int i=hd[u];i;i=nex[i])
	{
		int v=to[i];
		if(v==ff) continue; 
		dfs1(v,u); 
		siz[u]+=siz[v]; 
		if(siz[v]>siz[hson[u]]) hson[u]=v; 
	}
}
void dfs2(int u,int tp)
{
	top[u]=tp; 
	if(hson[u]) dfs2(hson[u],tp); 
	for(int i=hd[u];i;i=nex[i])
	{
		int v=to[i]; 
		if(v==fa[u]||v==hson[u]) continue; 
		dfs2(v,v); 
	}
}
int LCA(int x,int y)
{
	while(top[x]^top[y]) dep[top[x]] > dep[top[y]] ? x = fa[top[x]] : y = fa[top[y]]; 
	return dep[x] < dep[y] ? x : y; 
}
int Getdis(int x,int y)
{
	return dep[x] + dep[y] - (dep[LCA(x,y)]<<1); 
}
int main()
{
	// setIO("input"); 
	scanf("%d%d",&n,&Q);
	for(int i=1,u,v;i<n;++i)  
	{
		scanf("%d%d",&u,&v); 
		add(u,v), add(v,u); 
	}
	dfs1(1,0); 
	dfs2(1,1);    
	int u,v,t; 
	while(Q--)
	{
		scanf("%d%d%d",&u,&v,&t); 
		int d1=LCA(u,v),d2=LCA(u,t),cur,d3=LCA(v,t); 
		cur=dep[d1]<dep[d2]?d2:d1;
		cur=dep[cur]<dep[d3]?d3:cur; 
		printf("%d %d\n",cur,Getdis(u,cur)+Getdis(v,cur)+Getdis(t,cur)); 
	}
	return 0; 
}

  

 

posted @ 2019-06-13 07:40  EM-LGH  阅读(175)  评论(0编辑  收藏  举报