嘟嘟嘟




首先这题虽然不是很难,但是黄题是不是有点过分了……好歹算个蓝题啊。




手玩样例得知,这哥们儿瞬移到的城市\(A\)一定是这些被攻击的城市构成的树的一个叶子,然后他经过的最后一个城市\(B\)和\(A\)构成的链一定是这棵新构成的树的直径(突然想到虚树)。

别激动,这题根本不用虚树。

我们只用求一遍树的直径就行了,只不过这个直径的端点必须满足都是被攻击的城市,则第一问就是端点中的较小值。




考虑第二问。

直径上的城市只会走一遍,而直径外的城市必须走过去再回来。所以我们从直径一段开始遍历整个直径,每经过一个点,就dfs这个点直径之外的子树,并统计子树内走到被攻击的城市的距离和。那么答案就是这些距离+加树的直径长度。

距离和的求法用树形dp就行。我们考虑每一条边的贡献。如果一个点的的儿子的子树内有被攻击的城市,则这条边一定会被走过,答案加2即可。




然后记得特判被攻击的城市只有一个的情况(被hack了……)。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 2e5 + 5;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
} int n, m;
bool vis[maxn];
struct Edge
{
int nxt, to;
}e[maxn << 1];
int head[maxn], ecnt = -1;
In void addEdge(int x, int y)
{
e[++ecnt] = (Edge){head[x], y};
head[x] = ecnt;
} int dep[maxn], fa[maxn], Max = 0, A, B;
In void dfs1(int now, int _f, int dis, int& id)
{
if(vis[now] && (dis > Max || (dis == Max && now < id))) Max = dis, id = now;
dep[now] = dep[_f] + 1; fa[now] = _f;
for(int i = head[now], v; ~i; i = e[i].nxt)
if((v = e[i].to) ^ _f) dfs1(v, now, dis + 1, id);
} bool dia[maxn];
int a[maxn], b[maxn], acnt = 0, bcnt = 0;
In void solve(int x, int y)
{
a[++acnt] = x; b[++bcnt] = y;
dia[x] = dia[y] = 1;
while(x ^ y)
{
if(dep[x] > dep[y]) a[++acnt] = x = fa[x], dia[x] = 1;
else b[++bcnt] = y = fa[y], dia[y] = 1; }
--acnt;
} int ans = 0;
In bool dfs2(int now, int _f, int dis)
{
int flg = 0;
for(int i = head[now], v; ~i; i = e[i].nxt)
{
if(dia[v = e[i].to] || v == _f) continue;
int tp = dfs2(v, now, dis + 1);
if(tp) ans += 2;
flg |= tp;
}
return flg || vis[now];
} int main()
{
Mem(head, -1);
n = read(), m = read();
for(int i = 1; i < n; ++i)
{
int x = read(), y = read();
addEdge(x, y), addEdge(y, x);
}
for(int i = 1; i <= m; ++i) A = read(), vis[A] = 1;
dfs1(A, 0, 0, A), Max = 0, dfs1(A, 0, 0, B);
if(!A || !B) {printf("%d\n0\n", A | B); return 0;}
solve(A, B);
for(int i = 1; i <= acnt; ++i) dfs2(a[i], 0, 0); //这两行是遍历直径
for(int i = 1; i <= bcnt; ++i) dfs2(b[i], 0, 0);
write(min(A, B)), enter, write(ans + Max), enter;
return 0;
}

CF592D Super M的更多相关文章

  1. 树的直径-CF592D Super M

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

  2. 子类继承父类时JVM报出Error:Implicit super constructor People() is undefined for default constructor. Must define an explicit constructor

    当子类继承父类的时候,若父类没有定义带参的构造方法,则子类可以继承父类的默认构造方法 当父类中定义了带参的构造方法,子类必须显式的调用父类的构造方法 若此时,子类还想调用父类的默认构造方法,必须在父类 ...

  3. [LeetCode] Super Ugly Number 超级丑陋数

    Write a program to find the nth super ugly number. Super ugly numbers are positive numbers whose all ...

  4. Maven Super POM

    Maven super POM defines some properties. Three ways to find it ${M2_HOME}/lib/maven-model-builder-3. ...

  5. java基础 super 子类调用父类

    如果希望在子类中,去调用父类的构造方法,要求在子类的构造函数调用 example如下: package test; /* * 如果希望在子类中,去调用父类的构造方法,要求在子类的构造函数调用 * */ ...

  6. Python类中super()和__init__()的关系

    Python类中super()和__init__()的关系 1.单继承时super()和__init__()实现的功能是类似的 class Base(object): def __init__(sel ...

  7. java方法重载(overload)、重写(override);this、super关键简介

    一.方法重载: 条件:必须在一个类中,方法名称相同,参数列表不同(包括:数据类型.顺序.个数),典型案例构 造方重载.  注意:与返回值无关 二.方法重写: 条件: (1)继承某个类或实现某接口 (2 ...

  8. Java super关键字活用

    在实际开发中我们要自定义组件,就需要继承自某个组件类,如果我们自定义的这个组件类也需要像被继承的这个组件类一样,拥有丰富的构造方法. 关键字super的作用就更加显得尤为重要了,你可以在堆砌自己自定义 ...

  9. 深入super,看Python如何解决钻石继承难题 【转】

    原文地址 http://www.cnblogs.com/testview/p/4651198.html 1.   Python的继承以及调用父类成员 python子类调用父类成员有2种方法,分别是普通 ...

随机推荐

  1. ngnix 是什么

    Nginx系列(一)--nginx是什么? 发表于2015/7/1 7:57:58  14347人阅读 分类: Nginx Java 一.介绍 Nginx是一个高性能的HTTP和反向代理服务器,也是一 ...

  2. Switch在swift中的使用

    switch的简单使用: 相比 C 和 objective - C 中的 switch 语句,Swift 中的 switch 语句不会默认的掉落到每个 case 的下面进入 另一个 case.相反,第 ...

  3. 深入Spring Boot:那些注入不了的Spring占位符(${}表达式)

    Spring里的占位符 spring里的占位符通常表现的形式是: <bean id="dataSource" destroy-method="close" ...

  4. Nodejs.Electron(Nodejs的图形界面开发)安装和试用

    # 克隆示例项目的仓库 git clone https://github.com/electron/electron-quick-start # 进入这个仓库 cd electron-quick-st ...

  5. 字符串匹配KMP算法的讲解C++

    转自http://blog.csdn.net/starstar1992/article/details/54913261 也可以参考http://blog.csdn.net/liu940204/art ...

  6. BZOJ_3942_[Usaco2015 Feb]Censoring_KMP

    BZOJ_3942_[Usaco2015 Feb]Censoring_KMP Description 有一个S串和一个T串,长度均小于1,000,000,设当前串为U串,然后从前往后枚举S串一个字符一 ...

  7. 从构建分布式秒杀系统聊聊Disruptor高性能队列

    前言 秒杀架构持续优化中,基于自身认知不足之处在所难免,也请大家指正,共同进步.文章标题来自码友 简介 LMAX Disruptor是一个高性能的线程间消息库.它源于LMAX对并发性,性能和非阻塞算法 ...

  8. Python基础语法 系统学习

    Python 中的基础语法最大的特点就是优雅和简洁.入门学习Python的难度相比较其他语言也比较小. 我个人比较推荐以下三个学习方式(根据个人情况和喜好,可选择任意一个): 1.  菜鸟在线:出品的 ...

  9. Git详解及github与gitlab使用

    第一章 关于版本控制 第二章 GIT简介 第三章 GIT安装 第四章 初次运行GIT前配置 第五章 初始化仓库 第六章 GIT命令操作 第七章 GIT分支结构

  10. AngularJs 服务 广播

    1, angularJs的服务有provider,Service, Factory. Factory是对Service的封装,Service是对Provider的封装. Provide的源码如下: f ...