题意:给出一个无根树,点数为10^5,所有边的长度为1。给定其中有一些点是受到攻击的。

现在要求一个人选定一个点作为起点,走遍所有的受攻击点(不用再回到起点)。

需要的最短距离是多少,选定的起点是哪个。

分析:这是一个求树直径的变形题,原版请看这里

求树的直径即树中最远的点对,需要进行两次bfs或者dfs。这里我们用的是dfs。

首先我们假设所有点都受到攻击,那么要走完所有点再回到起点,路程L就是树上所有边的长度和乘以2。

不用回到起点遍历所有点的最短距离就是用这个L减去树上的最远两点之间的距离。

我们要把起点选在最远点对中的点才能保证所得解最小。

但本题中不是所有点都受到攻击,所以在求最远点对的时候要进行一些改变。要找最远的受攻击点对。

首先要以一个受攻击点为根(这个是本题最大难点,不太容易想到),进行第一次dfs,找到最深的受攻击点之后,再以它为根找最深的受攻击点。(注意长度相同时,找编号最小的)

再求出以任意受攻击点为根,遍历所有受攻击点的路程和。两者相减即为解。

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std; const int MAX_N = (int)(2e5) + ; int n, m;
int root;
vector<int> g[MAX_N];
bool attacked[MAX_N];
int depth[MAX_N];
long long path_len; void input()
{
scanf("%d%d", &n, &m);
for (int i = ; i < n - ; i++)
{
int a, b;
scanf("%d%d", &a, &b);
a--;
b--;
g[a].push_back(b);
g[b].push_back(a);
}
memset(attacked, , sizeof(attacked));
for (int i = ; i < m; i++)
{
int a;
scanf("%d", &a);
a--;
attacked[a] = true;
}
} void dfs(int u, int father)
{
for (int i = ; i < (int)g[u].size(); i++)
{
int v = g[u][i];
if (v == father)
continue;
depth[v] = depth[u] + ;
dfs(v, u);
}
} int find_next()
{
int ret = root;
for (int i = ; i < n; i++)
{
if (!attacked[i])
continue;
if (depth[i] > depth[ret] || (depth[i] == depth[ret] && i < ret))
{
ret = i;
}
}
return ret;
} bool cal_depth(int u, int father)
{
bool ret = false;
for (int i = ; i < (int)g[u].size(); i++)
{
int v = g[u][i];
if (v == father)
continue;
if (!cal_depth(v, u))
continue;
path_len += ;
ret = true;
}
return ret || attacked[u];
} int main()
{
input();
root = find(attacked, attacked + n, true) - attacked; depth[root] = ;
dfs(root, -);
root = find_next(); depth[root] = ;
dfs(root, -); int end = find_next();
int city = min(root, end);
path_len = ;
cal_depth(root, -);
printf("%d\n%I64d\n", city + , path_len - depth[end]);
return ;
}

cf592d的更多相关文章

  1. CF592D Super M

    嘟嘟嘟 首先这题虽然不是很难,但是黄题是不是有点过分了--好歹算个蓝题啊. 手玩样例得知,这哥们儿瞬移到的城市\(A\)一定是这些被攻击的城市构成的树的一个叶子,然后他经过的最后一个城市\(B\)和\ ...

  2. 树的直径-CF592D Super M

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

随机推荐

  1. css样式中遇到!important

    链接: http://zhidao.baidu.com/link?url=XyYHS2l-bFkzEgMBWfbQYuEV4vmGz8kOhj-jDL_HBqu0KnVIBQJKvw5OOO-bVjv ...

  2. C#List的排序和简单去重总结

    List集合在开发过程中很常见,经常我们要对该集合进行一系列操作,本文介绍如何将该集合内的元素进行排序,博主制作简单WinForm应用程序进行演示. 首先,我们来看一下c#泛型List提供的Sort方 ...

  3. R语言学习笔记

    向量化的函数 向量化的函数 ifelse/which/where/any/all/cumsum/cumprod/对于矩阵而言,可以使用rowSums/colSums.对于“穷举所有组合问题" ...

  4. php 冒泡排序

    public function demo($arr){ $len = count($arr); if ($len == 1) { return $arr; } else { for ($i = 1; ...

  5. 原生JavaScript技巧大收集(11~20)-(终于又被我找到这篇文章了)

    11.原生JavaScript加入收藏夹 function AddFavorite(sURL, sTitle) { try { window.external.addFavorite(sURL, sT ...

  6. 大熊君大话NodeJS之------Stream模块

    一,开篇分析 流是一个抽象接口,被 Node 中的很多对象所实现.比如对一个 HTTP 服务器的请求是一个流,stdout 也是一个流.流是可读,可写或兼具两者的. 最早接触Stream是从早期的un ...

  7. ELK常见错误分析(转)

    ELK 常见错误处理   ELK 这里就不介绍了,如何安装请参考博客之前的文章.在这里感谢ttlsa团队,同时,我很荣幸能加入到ttlsa团队中,分享点滴,凉白开说发文章有红包,期待这篇群主能给多少红 ...

  8. mongodb_修改器($inc/$set/$unset/$push/$pop/upsert......)

    主从复制:http://blog.csdn.net/drifterj/article/details/7833883 对于文档的更新除替换外,针对某个或多个文档只需要部分更新可使用原子的更新修改器,能 ...

  9. Problem B Boxes in a Line

     省赛B题....手写链表..其实很简单的.... 比赛时太急了,各种手残....没搞出来....要不然就有金了...注:对相邻的元素需要特判..... Problem B Boxes in a Li ...

  10. JS补充

    JavaScript JavaScript 使用那些老旧的实例可能会在 <script> 标签中使用 type="text/javascript".现在已经不必这样做了 ...