「AHOI2008」「LuoguP4281」紧急集合 / 聚会(LCA

题目描述

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

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

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

输入输出格式

输入格式:

第一行两个正整数N和M(N<=500000,M<=500000),之间用一个空格隔开。分别表示等待点的个数(等待点也从1到N进行编号)和获奖所需要完成集合的次数。
随后有N-1行,每行用两个正整数A和B,之间用一个空格隔开,表示编号为A和编号为B的等待点之间有一条路。
接着还有M行,每行用三个正整数表示某次集合前小可可、小可可的朋友以及你所在等待点的编号。

输出格式:

一共有M行,每行两个数P,C,用一个空格隔开。其中第i行表示第i次集合点选择在编号为P的等待点,集合总共的花费是C个游戏币。

输入输出样例

输入样例#1:
复制

6 4
1 2
2 3
2 4
4 5
5 6
4 5 6
6 3 1
2 4 4
6 6 6

输出样例#1: 复制

5 2
2 5
4 1
6 0

说明

提示:

40%的数据中N<=2000,M<=2000
100%的数据中,N<=500000,M<=500000


题解

对于每次询问,设三个点分别为x1,x2,x3。

两两求lca,得到三个lca,其中最深的那个点为最优集合点。

不会严谨证明,画画图感性理解还是不难的。

然后有了集合点,问题转化为求树上两点间的距离。

随便搞搞就出来了。

  1 /*
  2     qwerta
  3     P4281 [AHOI2008]紧急集合 / 聚会
  4     Accepted
  5     100
  6     代码 C++,2.24KB
  7     提交时间 2018-10-09 18:50:02
  8     耗时/内存
  9     1148ms, 24100KB
 10 */
 11 #include<iostream>
 12 #include<cstdio>
 13 using namespace std;
 14 inline int read()
 15 {
 16     char ch=getchar();
 17     int x=0;
 18     while(!isdigit(ch))ch=getchar();
 19     while(isdigit(ch)){x=x*10+ch-‘0‘;ch=getchar();}
 20     return x;
 21 }
 22 const int MAXN=500003;
 23 struct emm{
 24     int e,f;
 25 }a[2*MAXN];
 26 int h[MAXN];
 27 int fa[MAXN],top[MAXN],d[MAXN],siz[MAXN],z[MAXN];
 28 void dfs(int x)
 29 {
 30     siz[x]=1,top[x]=x;
 31     int mac=0,macc=0;
 32     for(int i=h[x];i;i=a[i].f)
 33     if(!d[a[i].e])
 34     {
 35         d[a[i].e]=d[x]+1;
 36         fa[a[i].e]=x;
 37         dfs(a[i].e);
 38         siz[x]+=siz[a[i].e];
 39         if(siz[a[i].e]>macc){mac=a[i].e,macc=siz[a[i].e];}
 40     }
 41     z[x]=mac,top[mac]=x;
 42     return;
 43 }
 44 int q[MAXN],dfn[MAXN];
 45 int tot=0;
 46 void dfss(int x)
 47 {
 48     q[++tot]=x;
 49     dfn[x]=tot;
 50     if(z[x])dfss(z[x]);
 51     for(int i=h[x];i;i=a[i].f)
 52     if(fa[a[i].e]==x&&a[i].e!=z[x])
 53     dfss(a[i].e);
 54     return;
 55 }
 56 int fitop(int x)
 57 {
 58     if(top[x]==x)return x;
 59     return top[x]=fitop(top[x]);
 60 }
 61 int lca(int u,int v)//树剖求lca
 62 {
 63     while(top[u]!=top[v])
 64     {
 65         if(d[top[u]]<d[top[v]])swap(u,v);
 66         u=fa[top[u]];
 67     }
 68     if(d[u]<d[v])swap(u,v);
 69     return v;
 70 }
 71 int dmin(int x1,int x2,int x3)//找深度最深的点
 72 {
 73     if(d[x1]>=d[x2]&&d[x1]>=d[x3])return x1;
 74     if(d[x2]>=d[x1]&&d[x2]>=d[x3])return x2;
 75     return x3;
 76 }
 77 int dis(int u,int v)//求距离
 78 {
 79     int ans=0;
 80     while(top[u]!=top[v])
 81     {
 82         if(d[top[u]]<d[top[v]])swap(u,v);
 83         ans+=dfn[u]-dfn[top[u]]+1;
 84         u=fa[top[u]];
 85     }
 86     if(d[u]<d[v])swap(u,v);
 87     ans+=dfn[u]-dfn[v];
 88     return ans;
 89 }
 90 void write(int x)
 91 {
 92     if(x>9)write(x/10);
 93     putchar(x%10+‘0‘);
 94     return;
 95 }
 96 int main()
 97 {
 98     //freopen("a.in","r",stdin);
 99     int n=read(),m=read();
100     tot=0;
101     for(int i=1;i<n;++i)
102     {
103         int u=read(),v=read();
104         a[++tot].f=h[u];
105         h[u]=tot;
106         a[tot].e=v;
107         a[++tot].f=h[v];
108         h[v]=tot;
109         a[tot].e=u;
110     }
111     int s=min(n,7);//幸运数赛高!(逃
112     d[s]=1;
113     dfs(s);
114     tot=0;
115     dfss(s);
116     for(int i=1;i<=n;++i)
117     top[i]=fitop(i);
118     for(int i=1;i<=m;++i)
119     {
120         int x1=read(),x2=read(),x3=read();
121         int l1=lca(x1,x2),l2=lca(x2,x3),l3=lca(x1,x3);//两两取lca
122         int p=dmin(l1,l2,l3);//取最深的为集合点
123         int ans=dis(x1,p)+dis(x2,p)+dis(x3,p);//算距离,加起来
124         write(p);
125         putchar(‘ ‘);
126         write(ans);
127         putchar(‘\n‘);//输出
128     }
129     return 0;
130 }

原文地址:https://www.cnblogs.com/qwerta/p/9769506.html

时间: 2024-08-26 15:30:44

「AHOI2008」「LuoguP4281」紧急集合 / 聚会(LCA的相关文章

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

题目描述 欢乐岛上有个非常好玩的游戏,叫做"紧急集合".在岛上分散有 n 个等待点,有 n?1 条道路连接着它们,每一条道路都连接某两个等待点,且通过这些道路可以走遍所有的等待点,通过道路从一个点到另一个点要花费一个游戏币. 参加游戏的人三人一组,开始的时候,所有人员均任意分散在各个等待点上(每个点同时允许多个人等待),每个人均带有足够多的游戏币(用于支付使用道路的花费).地图(标明等待点之间道路连接的情况)以及对话机(用于和同组的成员联系).当集合号吹响后,每组成员之间迅速联系,了解

CSS无需Webfont实现近似「微软雅黑Light」的字体效果

在网页制作中,美观的字体能很大程度上提升一个网页的整体外观浏览效果(说白了就是提升逼格),但受各种因素的影响(例如中文字体应用Webfont的麻 烦),使开发者在制作过程中不得不使用“Web安全字体”,这使网页的外观效果大幅下降.今天在改模板的过程中偶然发现一个很笨的方法,实现近似微软雅黑 Light的字体效果. 实际上「微软雅黑Light」字体就是相对于「微软雅黑」字体较细,但是它的显示效果却要让人觉得舒适很多,只要字体不会太小,显示效果还是不错的. 所以直接用font-weight属性设置字

Linux 小知识翻译 - 「协议(protocol)」

对于理解服务器和网络来说,「协议」是不可缺少的概念. 「协议(protocol)」有「规则,规定」的意思. 实际上「协议」的函数很广,在通信领域,「协议」规定了「在通信时,什么样的情况下,以什么样的顺序,什么样的方式交互什么样的数据」. 抽象的去理解「协议」可能会比较困难,下面来举个例子. 通过Web以HTML方式交互时使用的协议是「HTTP」(Hyper Text Transfer Protocol).这个协议最重要的就是规定了服务器和客户端之间以HTML方式交互的规则. 比如,客户端连接上服

「BZOJ」「3262」陌上花开

CDQ分治 WA :在solve时,对y.z排序以后,没有处理「y.z相同」的情况,也就是说可能(1,2,3)这个点被放到了(2,2,3)的后面,也就是统计答案在前,插入该点在后……也就没有统计到! sad 1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<iostream> 5 #include<algorithm> 6 using namespace s

苹果搜索广告后台大揭秘,最全最细致详解,手把手设置教程「后附官方视频」-b

WWDC2016 搜索广告分会视频和 PPT 发布了,ASO100 带开发者第一时间了解 Search Ads 后台设置(文末有原声视频). 首先介绍一下搜索广告的模式和竞价规则 广告模式为 CPT(Cost Per Tap,按点击收费),类似于国内的 CPC 广告模式.广告的展示受两个因素的影响:相关性与出价. 如下图,所有相关性低的广告都不被展示(无论出价高低),相关性相差不多时,展示出价高的广告. 苹果根据两方面来判断相关性,一是 App 文本的元数据(来源于描述等位置),二是用户点击广告

翻译「C++ Rvalue References Explained」C++右值引用详解 Part1:概述

本文系对「C++ Rvalue References Explained」 该文的翻译,原文作者:Thomas Becker. 该文较详细的解释了C++11右值引用的作用和出现的意义,也同时被Scott Meyers推荐,全文共分11个部分,我将利用业余时间,分别翻译. 受笔者水平所限,可能叙述会出现些许问题,还望多多指正. 部分名词为了保持含义和方便理解,并未翻译成中文,有的在括号内给出了常见的中文翻译. 目录 概述 Move语义 右值引用 强制Move语义 右值引用就是右值吗? Move语义

XCActionBar 「Xcode 中的 Alfred」

下载地址:https://github.com/pdcgomes/XCActionBar 基本命令: (1)「command+shift+8」或者双击「command」键可以打开「动作输入框窗口」 (2)「command+option+7」或者双击「alt」键可以执行「上次的动作」 编程时可用于双击或三击事件的按键分别为如下5个: (1)「alt」:NSAlternateKeyMask (2)「command」:NSCommandKeyMask (3)「control」:NSControlKey

通俗解释「为什么数据库难以拓展」

"如何通俗解释「为什么数据库难以拓展」",这个问题来自 Quora,题主还补充说自己有一些数据库的基本知识,但依然不理解为什么扩展数据库如此困难.伯乐在线编译摘编了这个问答贴的两个热门回复. Paul King , Facebook 数据科学家(3.6K 赞) 要扩展数据库有四大挑战:搜索.并发性.一致性和速度. 假设你有一张清单,上面有10个人名.如果你想要查找某个人,只需要看一眼清单就行. 但如果清单上有100万个人名呢?这时,你就需要一些策略了.电话簿把人名按照字母顺序排列,这样

Linux 小知识翻译 - 「内核(kernel)」

上次介绍了Linus Torvalds, 这次介绍他开发的「内核」. 经常听人提到「Linux kernel」,但如果被问到「kernel究竟是什么?」的话,会出乎意料的觉得难以回答. 那么,kernel到底是什么呢?「kernel」翻译过来就是「核心」的意思,简单来说,「Linux的核心程序就是Linux kernel」. 其实严格来说,「Linux」就是指「Linux kernel」.(最近,「Linux发行版」简称为「Linux」的情况越来越多) 将Linux kernel解释成「系统核心