嘟嘟嘟




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




手玩样例得知,这哥们儿瞬移到的城市\(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. CUDA编程模型之内存管理

    CUDA编程模型假设系统是由一个主机和一个设备组成的,而且各自拥有独立的内存. 主机:CPU及其内存(主机内存),主机内存中的变量名以h_为前缀,主机代码按照ANSI C标准进行编写 设备:GPU及其 ...

  2. Spring Security 源码分析(四):Spring Social实现微信社交登录

    社交登录又称作社会化登录(Social Login),是指网站的用户可以使用腾讯QQ.人人网.开心网.新浪微博.搜狐微博.腾讯微博.淘宝.豆瓣.MSN.Google等社会化媒体账号登录该网站. 前言 ...

  3. PyCharm 专题

    pycharm常用设置 pycharm中的设置是可以导入和导出的,file>export settings可以保存当前pycharm中的设置为jar文件,重装时可以直接import settin ...

  4. c# Socket通信异步TCP

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.N ...

  5. 用react重构个人网站 3-22

    问题一:import React from 'react'这个写法是怎么回事? 答案:require是common.js的写法,import是ES6的写法,主要功能都是引入模块,写法上: var mo ...

  6. app后端设计(3)--短信,邮件,推送服务(2014.12.05更新)

    在app的后端设计中,免不了消息的推送,短信,邮件等服务,下面就个人的开发经验谈谈这方面. (1)最重要的是,各种推送一定要放在队列系统中处理,不然会严重影响api的响应时间. (2)短信方面 以前我 ...

  7. 解决centos7 python3 上下左右变ABCD

    首先:rpm -qa | grep readline //查看有没有安装readline-devel(出现标题的问题就是因为没有安装readline-devel包) 其次:使用yum search r ...

  8. Java 读书笔记 (十七) Java 重写(Override)与重载(Overload)

    重写(Override) 重写是子类对父类的允许访问的方法的实现过程重新编写,返回值和形参都不能改变,即外壳不变,核心重写. // 如果重写不是相当于重新定义了一个方法?那为什么不直接写,还要exte ...

  9. nsq源码阅读笔记之nsqd(三)——diskQueue

    diskQueue是backendQueue接口的一个实现.backendQueue的作用是在实现在内存go channel缓冲区满的情况下对消息的处理的对象. 除了diskQueue外还有dummy ...

  10. Executor框架简介

    Executor框架是在Java5中引入的,可以通过该框架来控制线程的启动,执行,关闭,简化并发编程.Executor框架把任务提交和执行解耦,要执行任务的人只需要把任务描述清楚提交即可,任务的执行提 ...