BZOJ 1787: [Ahoi2008]Meet 紧急集合
题目描述
欢乐岛上有个非常好玩的游戏,叫做“紧急集合”。在岛上分散有N个等待点,有N-1条道路连接着它们,每一条道路都连接某两个等待点,且通过这些道路可以走遍所有的等待点,通过道路从一个点到另一个点要花费一个游戏币。
参加游戏的人三人一组,开始的时候,所有人员均任意分散在各个等待点上(每个点同时允许多个人等待),每个人均带有足够多的游戏币(用于支付使用道路的花费)、地图(标明等待点之间道路连接的情况)以及对话机(用于和同组的成员联系)。当集合号吹响后,每组成员之间迅速联系,了解到自己组所有成员所在的等待点后,迅速在N个等待点中确定一个集结点,组内所有成员将在该集合点集合,集合所用花费最少的组将是游戏的赢家。
小可可和他的朋友邀请你一起参加这个游戏,由你来选择集合点,聪明的你能够完成这个任务,帮助小可可赢得游戏吗?
题解:
Code:
#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;
}