• 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);
    	}
    }
    
  • 相关阅读:
    STM32时钟树
    js jQuery函数 $.ajax()
    jQuery 语法
    jQuery介绍
    python笔记2 生成器 文件读写
    python笔记1,语法,函数,类和实例,异常
    Scrapy爬虫入门系列4抓取豆瓣Top250电影数据
    Scrapy爬虫入门系列3 将抓取到的数据存入数据库与验证数据有效性
    opus 规范 与参数解析
    开源播放器ijkplayer源码结构
  • 原文地址:https://www.cnblogs.com/naruto-mzx/p/12665861.html
Copyright © 2020-2023  润新知