给定一颗n个节点树,边权为1,树上有m个点被标记,问从树上一个点出发,经过所有被标记的点的最短路程(起终点自选)。同时输出可能开始的编号最小的那个点。M<=N<=123456。

  先想:如果所有点都被标记那么怎么样?我们发现对于起点s终点t,如果它们在同一条链上,那么必须先从s往外走,再回来,再经过t,再回到t。走过的路径就是树上所有边*2-s到t的路径。如果它们不在同一条链上,那么s在走到t的过程中访问所有点,走过的路径还是树上所有边*2-s到t的路径。

  于是如果所有点都被标记,我们应该找到树的直径。如何找树的直径呢?先随便找一个点,然后找从这个点出发能到达的最远点。这个最远点一定是直径的一段,然后再找一次直径即可。(待证)

  所以我们只需要把这棵树转成全被标记的就行了。我们随便找一个标记过的点,将其作为树的根,然后只保留标记各个点所在的那条链的上端,因为它们是唯一且一定会经过的边。然后按照算法来就行了。

  但这样做还不够,题目还要求输出可能开始的编号最小的那个点。我们发现如果第一次从根开始找,编号最小的点要么是离根最远的点,要么是离根最远的点所找到的最远的点。而离根最远的点能找到的最远的点实际上都是一样的,这就告诉我们直接取最小编号的点,再找一遍,再取最小值就行了。

  给出我丑陋的代码:

#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std; const int maxn=;
int n, m, root, printed_num, longest_road;
int printed_list[maxn], printed[maxn], visited[maxn], step[maxn];
vector<int> node[maxn], sons[maxn];
queue<int> q; int make_tree(int pos){
int return_value=, t=, nowson;
visited[pos]=;
for (int i=; i<node[pos].size(); ++i){
nowson=node[pos][i];
if (visited[nowson]) {
sons[pos].push_back(nowson);
continue;
}
t=make_tree(nowson);
if (t) sons[pos].push_back(nowson);
return_value|=t;
}
if (printed[pos]) return_value=;
if (return_value) ++printed_num;
return return_value;
} int main(){
scanf("%d%d", &n, &m);
int t1, t2;
for (int i=; i<n; ++i){
scanf("%d%d", &t1, &t2);
node[t1].push_back(t2);
node[t2].push_back(t1);
}
for (int i=; i<m; ++i){
scanf("%d", &printed_list[i]);
printed[printed_list[i]]=;
}
make_tree(printed_list[]);
if (printed_num==) {
printf("%d\n%d\n", printed_list[], );
return ;
}
root=printed_list[];
memset(visited, , sizeof(visited));
q.push(root);
int nownode, nowson, farthest=, farone=;
while (!q.empty()){
nownode=q.front();
q.pop();
visited[nownode]=;
for (int i=; i<sons[nownode].size(); ++i){
nowson=sons[nownode][i];
if (visited[nowson]) continue;
step[nowson]=step[nownode]+;
q.push(nowson);
}
if (step[nownode]>farthest){
farthest=step[nownode];
farone=nownode;
}
if (step[nownode]==farthest&&farone>nownode)
farone=nownode;
}
int a, b;
a=farone;
farthest=, farone=;
while (!q.empty()) q.pop();
memset(visited, , sizeof(visited));
memset(step, , sizeof(step));
q.push(a);
while (!q.empty()){
nownode=q.front();
q.pop();
visited[nownode]=;
for (int i=; i<sons[nownode].size(); ++i){
nowson=sons[nownode][i];
if (visited[nowson]) continue;
q.push(nowson);
step[nowson]=step[nownode]+;
}
if (step[nownode]>farthest){
farthest=step[nownode];
farone=nownode;
}
if (step[nownode]==farthest&&farone>nownode)
farone=nownode;
}
b=farone;
if (a<b) printf("%d\n", a);
else printf("%d\n", b);
printf("%d", *(printed_num-)-farthest);
return ;
}

树的直径-CF592D Super M的更多相关文章

  1. Codeforces 592D - Super M - [树的直径][DFS]

    Time limit 2000 ms Memory limit 262144 kB Source Codeforces Round #328 (Div. 2) Ari the monster is n ...

  2. CodeForces - 592D: Super M(虚树+树的直径)

    Ari the monster is not an ordinary monster. She is the hidden identity of Super M, the Byteforces’ s ...

  3. 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分

    树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...

  4. poj2631 求树的直径裸题

    题目链接:http://poj.org/problem?id=2631 题意:给出一棵树的两边结点以及权重,就这条路上的最长路. 思路:求实求树的直径. 这里给出树的直径的证明: 主要是利用了反证法: ...

  5. poj1985 Cow Marathon (求树的直径)

    Cow Marathon Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 3195   Accepted: 1596 Case ...

  6. VIJOS1476旅游规划[树形DP 树的直径]

    描述 W市的交通规划出现了重大问题,市政府下决心在全市的各大交通路口安排交通疏导员来疏导密集的车流.但由于人员不足,W市市长决定只在最需要安排人员的路口安放人员.具体说来,W市的交通网络十分简单,它包 ...

  7. poj2631 树的直径

    设s-t是这棵树的直径,那么对于任意给予的一点,它能够到达的最远的点是s或者t. 这样我们可以通过2次bfs找到树的直径了. #include<cstdio> #include<qu ...

  8. 【BZOJ-1912】patrol巡逻 树的直径 + DFS(树形DP)

    1912: [Apio2010]patrol 巡逻 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1034  Solved: 562[Submit][St ...

  9. 牡丹江.2014B(图论,树的直径)

    B - Building Fire Stations Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%lld & ...

随机推荐

  1. python代码docstring生成文档之sphinx

    在使用python中,我们一般在模块,类,函数下使用docstring添加字符串说明性文档,使开发人员更好的可以看懂此代码是做什么用的.然而写了那么多的注释,我们想要一篇文档怎么办,第一种办法不可能将 ...

  2. ES _source字段介绍——json文档,去掉的话无法更新部分文档,最重要的是无法reindex

    摘自:https://es.xiaoleilu.com/070_Index_Mgmt/31_Metadata_source.html The _source field stores the JSON ...

  3. Logiscope学习网址

    Logiscope测试机理   http://blog.csdn.net/cmy673986/article/details/9163247 http://www.cnitblog.com/qiuya ...

  4. Java企业微信开发_00_源码及资源汇总贴

    一.源码 此系列教程的源码我都放在了github上,欢迎fork以及关注. 传送门:https://github.com/shirayner/WeiXin_QiYe_Demo/tree/master ...

  5. php 冒泡排序原理

    $start = microtime(true);   $popArr = array(6,3,23,1,5,100,399,99,66);   echo '6,3,23,1,5,100,399,99 ...

  6. freeMarker(十六)——FAQ

    学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net 1.JSP 和 FreeMarker ? 我们比较 FreeMarke ...

  7. 配置 VS Code 调试 PHP

    配置 VS Code 调试 PHP 1.下载 xampp 集成服务器wampserver3.1.0-Apache2.4.7_PHP5.6.3-7.0.23-7.1.19_MySQL5.7.19_Mar ...

  8. Android App在Google App Store中搜不到

    情景:Android App在Google App Store上架成功,三星手机可以在Google App Store中搜索到,但是三星tablet却无法在Google App Store中搜索到,目 ...

  9. BZOJ3401:[USACO2009MAR]Look Up

    浅谈栈:https://www.cnblogs.com/AKMer/p/10278222.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?id ...

  10. 编写dockerfile

    参考:http://www.cnblogs.com/liuyansheng/p/6098470.html 一.dockerfile介绍: 是一种被Docker程序解释的脚本,Dockerfile由一条 ...