Codeforces 592D - Super M - [树的直径][DFS]
Time limit 2000 ms
Memory limit 262144 kB
Source Codeforces Round #328 (Div. 2)
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.
Example
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个节点,n-1条边;
在这棵树上有m个标记的节点,有个叫SpuerM的人要从某一个点出发走遍所有标记点;
问从哪个点走能使得走过路径长度最短,输出起点编号(若有多个点都能作为起点,选编号最小的)和该路径长度。
题解:
看完题,一看这棵树的规模,心里有底——大概就O(N)的算法可以过,再看是一棵树,若要利用树的性质去求节点间的距离,又只能用O(N)的算法……
瞬间想起有关树的直径和DFS,翻到之前的博文:http://www.cnblogs.com/dilthey/p/7231438.html
那么怎么样才能利用上树的直径的性质呢?
考虑我们可以从m个标记点中任选一个作为树根,DFS产生一棵“新树”,剥离那些不可能去走的节点和边;
然后就可以再用两次DFS求得这棵新树的直径;
(原本考虑用树形DP求直径,但是这样一来似乎无法求得直径的端点,就得不到答案要求的起点编号;
而如果用两次DFS的话,两次for循环遍历寻找endpoint的过程,可以保证寻找到的endpoint是编号最小的,就能同时求得树的直径长度和编号最小的直径端点,正好满足题目要求.)
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = ; int n,m;
int newTreeEdgeNum;
bool attack[maxn],keep[maxn]; struct Edge{
int u,v;
};
vector<Edge> E;
vector<int> G[maxn];
void addedge(int u,int v)
{
E.push_back((Edge){u,v});
E.push_back((Edge){v,u});
int _size=E.size();
G[u].push_back(_size-);
G[v].push_back(_size-);
} bool dfs(int now,int par)//返回now这个节点是否保留
{
int _size=G[now].size(); bool flag=;
for(int i=;i<_size;i++)
{
Edge& e=E[G[now][i]]; int nxt=e.v;
if(nxt==par) continue;
if(dfs(nxt,now) && flag==) flag=;
}
keep[now]=(flag||attack[now]); if(keep[now] && par) newTreeEdgeNum++;
return keep[now];
} int dist[maxn];
void newTreeDFS(int now,int par)
{
if(!keep[now]) return;
for(int i=;i<G[now].size();i++)
{
Edge& e=E[G[now][i]]; int nxt=e.v;
if(nxt==par || !keep[nxt]) continue;
dist[nxt]=dist[now]+;
newTreeDFS(nxt,now);
}
} int main()
{
scanf("%d%d",&n,&m);
for(int i=,u,v;i<=n-;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
}
memset(attack,,sizeof(attack));
int root=;
for(int i=,tmp;i<=m;i++)
{
scanf("%d",&tmp);
attack[tmp]=;
if(root==) root=tmp;
} memset(keep,,sizeof(keep));
newTreeEdgeNum=;
keep[root]=dfs(root,); /* 关于新树的debug
for(int i=1;i<=n;i++) printf("attack[%d]=%d\n",i,attack[i]); //检查被攻击城市
for(int i=1;i<=n;i++) printf("keep[%d]=%d\n",i,keep[i]); //检查新树保留节点
printf("newTreeEdgeNum=%d\n\n",newTreeEdgeNum);
*/ dist[root]=;
newTreeDFS(root,);
int endpoint1;
for(int i=,maxi=-;i<=n;i++)
{
if(!keep[i]) continue;
if(dist[i]>maxi)
{
maxi=dist[i];
endpoint1=i;
}
} dist[endpoint1]=;
newTreeDFS(endpoint1,);
int endpoint2;
for(int i=,maxi=-;i<=n;i++)
{
if(!keep[i]) continue;
if(dist[i]>maxi)
{
maxi=dist[i];
endpoint2=i;
}
} printf("%d\n",min(endpoint1,endpoint2));
printf("%d\n",*newTreeEdgeNum-dist[endpoint2]);
}
PS.通过这道题,也算是把有关树的直径的问题好好巩固了一下,还是不错的!
Codeforces 592D - Super M - [树的直径][DFS]的更多相关文章
- CodeForces - 592D: Super M(虚树+树的直径)
Ari the monster is not an ordinary monster. She is the hidden identity of Super M, the Byteforces’ s ...
- Codeforces 455C Civilization:树的直径 + 并查集【合并树后直径最小】
题目链接:http://codeforces.com/problemset/problem/455/C 题意: 给你一个森林,n个点,m条边. 然后有t个操作.共有两种操作: (1)1 x: 输出节点 ...
- 【BZOJ-1912】patrol巡逻 树的直径 + DFS(树形DP)
1912: [Apio2010]patrol 巡逻 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 1034 Solved: 562[Submit][St ...
- 历届试题 大臣的旅费-(树的直径+dfs)
问题描述 很久以前,T王国空前繁荣.为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市. 为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首 ...
- 【lightoj-1094】树的直径(DFS)
链接:http://www.lightoj.com/volume_showproblem.php?problem=1094 题意: 一共n各节点编号0-n-1, 输入n-1条无向边代表u-v距离为w, ...
- CodeForces - 592D Super M 题解
题目大意: 一棵树 n个点 有m个点被标记 求经过所有被标记的点的最短路径的长度以及起点(如有多条输出编号最小的起点). 思路: 1.当且仅当一个点本身或其子树中有点被标记时该点在最短的路径上因此,可 ...
- codeforces GYM 100781A【树的直径】
先求出每棵树的直径,排个序,要想图的直径最小的话需要每棵树的直径中点像直径最大的树的直径中点连边,这样直径有三种情况:是直径最大的树的直径:a[tot]:是直径最大的树和直径第二大的树的半径拼起来+1 ...
- 图论--树的直径--DFS+树形DP模板
#include <iostream> #include <cstring> using namespace std; //maxv:源点能到的最远点,maxdis:最远点对应 ...
- Codeforces 14D Two Paths 树的直径
题目链接:点击打开链接 题意:给定一棵树 找2条点不反复的路径,使得两路径的长度乘积最大 思路: 1.为了保证点不反复,在图中删去一条边,枚举这条删边 2.这样得到了2个树,在各自的树中找最长链.即树 ...
随机推荐
- Android的WebView控件载入网页显示速度慢的究极解决方案
Android的WebView控件载入网页显示速度慢的究极解决方案 [转载来源自http://hi.baidu.com/goldchocobo/] 秒(甚至更多)时间才会显示出来.研究了很久,搜遍了国 ...
- SVN的Hooks功能--强制添加注释
所谓hooks,可以类似 理解Linux内核Netfilter框架的hook点和hook函数的概念.当用户在维护代码的过程中,其执行的相关动作正好触发了相关hook点,就 会去执行对应hook点的脚本 ...
- Tomcat catalina-deamon.out 日志切割 每天生成一个文件
Tomcat 使用 jsvc 以守护进程的方式启动(daemon.sh ).这样tomcat自身将会生成另外一个日志文件(catalina-daemon.out),而不是之前的catalina.out ...
- 消息中间件activemq-5.14.1安全验证配置
activemq分为控制端和客户端,下面分别介绍安全认证配置方法. 1.控制端安全配置 (1). ActiveMQ目录conf下找到jetty.xml: <bean id="secur ...
- 在SELECT DISTINCT 状况下使用 Order BY Newid() 随机数选出记录
在日常作业中,有时候可能是一些活动要抽出得奖人或选出抽查的一些名单, 就常常会使用到 Order BY Newid() 的方式来做随机数选出, 但有可能的状况需是要搭配到 DISTINCT 来选出,这 ...
- Ansible的快速入门
Ansible 是一个简单的自动化引擎,可完成配置管理,应用部署,服务编排等各种IT需求. Ansible使用python语言开发实现的开源软件,依赖于Jinjia2,paramiko和PyYAML这 ...
- React Native 入门到原理(详解)
抛砖引玉(帮你更好的去理解怎么产生的 能做什么) 砖一.动态配置 由于 AppStore 审核周期的限制,如何动态的更改 app 成为了永恒的话题.无论采用何种方式,我们的流程总是可以归结为以下三部曲 ...
- 【架构师之路】 LVS+Keepalived实现高可用负载均衡
一.原理 1.概要介绍 如果将TCP/IP划分为5层,则Keepalived就是一个类似于3~5层交换机制的软件,具有3~5层交换功能,其主要作用是检测web服务器的状态, ...
- 【cs229-Lecture3】为什么要选择“最小二乘法”这个指标
视频地址:http://v.163.com/movie/2008/1/E/B/M6SGF6VB4_M6SGHM4EB.html 具体的推导过程,讲义上都有,已经很详细了.这里的推导过程大都是自己为了练 ...
- delphi xe 怎么生成apk
f9 运行: 让它执行install[如果没有连接到android环境,会提示安装失败]或, 就在bin下面产生一个apk文件了:好像单单build是没法产生的.