CodeForces - 592D: Super M(虚树+树的直径)
Ari the monster is not an ordinary monster. She is the hidden identity of Super M, the Byteforces’ superhero. Byteforces is a country that consists of n cities, connected by n - 1 bidirectional roads. Every road connects exactly two distinct cities, and the whole road system is designed in a way that one is able to go from any city to any other city using only the given roads. There are m cities being attacked by humans. So Ari... we meant Super M have to immediately go to each of the cities being attacked to scare those bad humans. Super M can pass from one city to another only using the given roads. Moreover, passing through one road takes her exactly one kron - the time unit used in Byteforces.
However, Super M is not on Byteforces now - she is attending a training camp located in a nearby country Codeforces. Fortunately, there is a special device in Codeforces that allows her to instantly teleport from Codeforces to any city of Byteforces. The way back is too long, so for the purpose of this problem teleportation is used exactly once.
You are to help Super M, by calculating the city in which she should teleport at the beginning in order to end her job in the minimum time (measured in krons). Also, provide her with this time so she can plan her way back to Codeforces.
Input
The first line of the input contains two integers n and m (1 ≤ m ≤ n ≤ 123456) - the number of cities in Byteforces, and the number of cities being attacked respectively.
Then follow n - 1 lines, describing the road system. Each line contains two city numbers ui and vi (1 ≤ ui, vi ≤ n) - the ends of the road i.
The last line contains m distinct integers - numbers of cities being attacked. These numbers are given in no particular order.
Output
First print the number of the city Super M should teleport to. If there are many possible optimal answers, print the one with the lowest city number.
Then print the minimum possible time needed to scare all humans in cities being attacked, measured in Krons.
Note that the correct answer is always unique.
Examples
7 2
1 2
1 3
1 4
3 5
3 6
3 7
2 7
2
3
6 4
1 2
2 3
2 4
4 5
4 6
2 4 5 6
2
4
Note
In the first sample, there are two possibilities to finish the Super M's job in 3 krons. They are:
and .
However, you should choose the first one as it starts in the city with the lower number.
题意:给定一棵大小为N的树,然后给定K个特殊点。现在让你在原树上任选一个点起点,然后从这个起点遍历所有的特殊点,走的最短路程是多少,选择的起点是哪个。如果多个起点满足题意,输出编号最小的那一个。
思路:假设必须要走的点组成的树大小为M,那么答案为M*2-dis,其中dis是起点和终点的距离。很显然是在所有必须走到的点中找到树的直径。
如果我们会虚树,那么我们可以很快地求出这棵树:首先把所有特殊点按照DFS序排序,把排序后相邻两点的LCA求出来,把这些LCA耶标记为特殊点,然后除了虚树的根节点,其他特殊点都可以一直向上连边,直到遇到下一个关键点。
(也有其他直接DFS得到这棵树的。假设多次询问,虚树的优点就显现出来了,特殊点连边的时候不需要把之间的非特殊点加进来,而是通过倍增得到距离,然后得到一颗点数不超过2*K个点的树。
#include<bits/stdc++.h>
const int maxn=;
using namespace std;
int Laxt[maxn],Next[maxn],To[maxn],in[maxn],a[maxn],cnt;
int vis[maxn],dep[maxn],fa[maxn][],dis[maxn],S,T,ans,times;
bool cmp(int x,int y) { return in[x]<in[y]; }
void add(int u,int v) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; }
void dfs(int u,int f)
{
in[u]=++times; fa[u][]=f; dep[u]=dep[f]+;
for(int i=Laxt[u];i;i=Next[i]){
if(To[i]!=f) dfs(To[i],u);
}
}
void dfs2(int u,int f)
{
dis[u]=dis[f]+;
for(int i=Laxt[u];i;i=Next[i]){
if(To[i]!=f) dfs2(To[i],u);
}
}
int LCA(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
for(int i=;i>=;i--) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
if(u==v) return u;
for(int i=;i>=;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
return fa[u][];
}
int main()
{
int N,M,tot,u,v,i,j;
scanf("%d%d",&N,&M);
for(i=;i<N;i++){
scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
dfs(,);
for(i=;i<=;i++)
for(j=;j<=N;j++)
fa[j][i]=fa[fa[j][i-]][i-];
for(i=;i<=M;i++) scanf("%d",&a[i]);
sort(a+,a+M+,cmp); tot=M;
for(i=;i<=M;i++) a[++tot]=LCA(a[i-],a[i]);
sort(a+,a+tot+,cmp);
tot=unique(a+,a+tot+)-(a+);
for(i=;i<=tot;i++) vis[a[i]]=; //得到关键点
memset(Laxt,,sizeof(Laxt)); cnt=;
for(i=;i<=tot;i++){ //关键点之间连边得到新树
u=a[i];
while(true){
if(u==a[]) break;
ans++;
add(u,fa[u][]); add(fa[u][],u);
u=fa[u][];
if(vis[u]||u==) break;
}
}
dfs2(a[],); //得到直径
for(i=;i<=tot;i++) if(dis[a[i]]>dis[S]||(dis[a[i]]==dis[S]&&a[i]<S)) S=a[i];
dis[S]=;
dfs2(S,);
for(i=;i<=tot;i++) if(dis[a[i]]>dis[T]||(dis[a[i]]==dis[T]&&a[i]<T)) T=a[i];
printf("%d\n%d\n",min(S,T),ans*-(dis[T]-));
return ;
}
CodeForces - 592D: Super M(虚树+树的直径)的更多相关文章
- Codeforces 592D - Super M - [树的直径][DFS]
Time limit 2000 ms Memory limit 262144 kB Source Codeforces Round #328 (Div. 2) Ari the monster is n ...
- CodeForces - 592D Super M 题解
题目大意: 一棵树 n个点 有m个点被标记 求经过所有被标记的点的最短路径的长度以及起点(如有多条输出编号最小的起点). 思路: 1.当且仅当一个点本身或其子树中有点被标记时该点在最短的路径上因此,可 ...
- CodeForces 592D Super M DP
Super M 题解: 定义 dp[u][0] 为遍历完u中的所有节点, 但不回到u点的路径花费值. 定义 dp[u][1] 为遍历完u中的所有节点, 且要回到u点的路径花费值. 转移方程. dp[u ...
- CodeForces 592D Super M
先把没用的边去掉,求出包含m个点的最小树.然后求出最小树的直径就可以得到答案了. #include <cstdio> #include <cstring> #include & ...
- 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分
树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...
- Codeforces 219D. Choosing Capital for Treeland (树dp)
题目链接:http://codeforces.com/contest/219/problem/D 树dp //#pragma comment(linker, "/STACK:10240000 ...
- Codeforces 633C Spy Syndrome 2 | Trie树裸题
Codeforces 633C Spy Syndrome 2 | Trie树裸题 一个由许多空格隔开的单词组成的字符串,进行了以下操作:把所有字符变成小写,把每个单词颠倒过来,然后去掉单词间的空格.已 ...
- codeforces Good bye 2016 E 线段树维护dp区间合并
codeforces Good bye 2016 E 线段树维护dp区间合并 题目大意:给你一个字符串,范围为‘0’~'9',定义一个ugly的串,即串中的子串不能有2016,但是一定要有2017,问 ...
- <虚树+树型DP> HNOI2014世界树
<虚树+树型DP> HNOI2014世界树 #include <iostream> #include <cstdio> #include <cstring&g ...
随机推荐
- typedef,结构体,共用体,联合体
typedef的用途: 封装数据类型,方便移植 简化函数指针的定义 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG90b3R1enVvcXVhbg==/ ...
- java Map 实现类的对比
java为数据结构中的映射定义了一个接口 java.util.Map ,他有四个实现类
- MFC——9.多线程与线程同步
Lesson9:多线程与线程同步 程序.进程和线程是操作系统的重点,在计算机编程中.多线程技术是提高程序性能的重要手段. 本文主要解说操作系统中程序.进程和线程之间的关系,并通过相互排斥对象和事件对象 ...
- unbuntu16.04上python开发环境搭建建议
unbuntu16.04上python开发环境搭建建议 2017-12-20 10:39:27 推荐列表: pycharm: 可以自行破解,但是不推荐,另外也不稳定 pydev+eclipse: ...
- 贷前系统ElasticSearch实践总结
贷前系统负责从进件到放款前所有业务流程的实现,其中涉及一些数据量较大.条件多样且复杂的综合查询,引入ElasticSearch主要是为了提高查询效率,并希望基于ElasticSearch快速实现一个简 ...
- ReactiveCocoa入门教程——第一部分【转载】
作为一个iOS开发者,你写的每一行代码几乎都是在响应某个事件,例如按钮的点击,收到网络消息,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation).但是这些事件都用不同的方式来处理 ...
- delphi 解析Json格式(转自:http://blog.csdn.net/jayqiang/article/details/7066824)
SuperObject 是开源的 Delphi 的 JSON 工具包,可生成 JSON 数据以及进行 JSON 解析. unit Unit6; interface uses Windows, Mess ...
- Hadoop常见异常及其解决方式
1.Shell$ExitCodeException 现象:执行hadoop job时出现例如以下异常: 14/07/09 14:42:50 INFO mapreduce.Job: Task Id : ...
- struts2 jsp提交日期类型转换及国际化实现
概述:下面通过jsp提交输入注册信息信息,同时完成过程文件国家化问题演示说明.[注册日期转换用注解方式实现] 工程截图: 注册页面jsp文件: <%@ page language="j ...
- Docker基础原理
前言 Docker是一个开源的软件项目,让用户程序部署在一个相对隔离的环境运行,借此在Linux操作系统上提供一层额外的抽象,以及操作系统层虚拟化的自动管理机制.需要额外指出的是,Docker并不等于 ...