luogu P4281 [AHOI2008]紧急集合 / 聚会 |LCA

Posted naruto-mzx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P4281 [AHOI2008]紧急集合 / 聚会 |LCA相关的知识,希望对你有一定的参考价值。

题目描述

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

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

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

输入格式

第一行两个正整数 n 和 m,分别表示等待点的个数(等待点也从 1 到 n 进行编号)和获奖所需要完成集合的次数。

随后 n?1 行,每行两个正整数 a,b,表示编号为 a 和编号为 b 的等待点之间有一条路。

随后 m 行,每行用三个正整数 x,y,z,表示某次集合前小可可、小可可的朋友以及你所在等待点的编号。

输出格式

输出共 m 行,每行两个用空格隔开的整数 p,c。其中第 i 行表示第 i 次集合点选择在编号为 p 的等待点,集合总共的花费是 c 个游戏币。


答案必然在某两个的LCA上

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5e5+10;
int nxt[N<<1],head[N],go[N<<1],tot;
inline int read(){
	int x=0; char c=getchar();
	while(c<‘0‘||c>‘9‘)c=getchar();
	while(‘0‘<=c&&c<=‘9‘){ x=(x<<1)+(x<<3)+c-‘0‘; c=getchar(); }
	return x;
}
inline void add(int u,int v){
	nxt[++tot]=head[u],head[u]=tot,go[tot]=v;
	nxt[++tot]=head[v],head[v]=tot,go[tot]=u;
}
int f[N][20],dep[N];
void Deal(int u,int fa){
	f[u][0]=fa,dep[u]=dep[fa]+1;
	for(int i=1;i<=19;i++)f[u][i]=f[f[u][i-1]][i-1];
	
	for(int i=head[u];i;i=nxt[i]){
		int v=go[i];
		if(v==fa)continue;
		Deal(v,u);
	}
	
}
inline int LCA(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	for(int i=19;i>=0;i--)if(dep[f[x][i]]>=dep[y])x=f[x][i];
	if(x==y)return x;
	for(int i=19;i>=0;i--)
	if(f[x][i]!=f[y][i]){
		x=f[x][i];
		y=f[y][i];
	}
	return f[x][0];
}
int n,m;
inline int dis(int x,int y){
	return dep[x]+dep[y]-2*dep[LCA(x,y)];
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<n;i++)add(read(),read());
	
	Deal(1,1);
	int x,y,z;
	while(m--){
		x=read(),y=read(),z=read();
		int ans=1e9,w,mzx;
		int a1=LCA(x,y),a2=LCA(x,z),a3=LCA(z,y);
		
		mzx=dep[x]+dep[y]-2*dep[a1]+dis(z,a1);
		if(ans>mzx)ans=mzx,w=a1;
		mzx=dep[x]+dep[z]-2*dep[a2]+dis(y,a2);
		if(ans>mzx)ans=mzx,w=a2;
		mzx=dep[z]+dep[y]-2*dep[a3]+dis(x,a3);
		if(ans>mzx)ans=mzx,w=a3;

		printf("%d %d
",w,ans);
	}
}

以上是关于luogu P4281 [AHOI2008]紧急集合 / 聚会 |LCA的主要内容,如果未能解决你的问题,请参考以下文章

[Ahoi2008]Meet 紧急集合

bzoj1787[Ahoi2008]Meet 紧急集合

bzoj 1787: [Ahoi2008]Meet 紧急集合

BZOJ-1787: [Ahoi2008]Meet 紧急集合 (LCA)

AHOI2008 紧急集合 树上倍增

[AHOI2008]紧急集合 / 聚会