题解 CF337D 【Book of Evil】
Description
题目链接
有
Solution
这里提供一种
找出在这颗树上距离最远的两只鬼,将它们的位置设为
- 如果某一个点到
A 和B 的距离都不超过d ,那么该点到其余鬼所在点的距离也不会超过d 。
否则,如果存在某一个鬼和该点的距离超过
考虑证明这一个性质。设该点为
- 设点
P 在A,B 路径上,设另有一只鬼在点C 。
反证法。假设
与
- 设点
P 在A,B 路径之外,设另有一只鬼在点C 。
这种情况中还包含着两种小情况,同样使用反证法。
- 若
P,C 两点间的路径和A,B 两点间的路径没有交点:
设有两点
假设
两边同时加上
与
- 若
P,C 两点间的路径和A,B 两点间的路径有交点,设交点为X :
假设
两边同时加上
与
考虑如何找到最远的两只鬼
于是这个问题可以转化为找到
总共三次 dfs,最后扫一遍所有点统计答案。总时间复杂度为
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define maxn 1000005
using namespace std;
inline int read()
{
int x = 0, w = 1;char ch = getchar();
while (ch > '9' || ch < '0') { if (ch == '-')w = -1;ch = getchar(); }
while (ch >= '0' && ch <= '9')x = x * 10 + ch - '0', ch = getchar();
return x * w;
}
struct node
{
int to, nxt;
}edge[maxn << 1];
int n, m, d, tot, tmp, ans;
int evil[maxn], dis1[maxn], dis2[maxn], head[maxn];
inline void add(int u, int v) { edge[++tot].nxt = head[u];edge[tot].to = v;head[u] = tot; }
inline void addedge(int u, int v) { add(u, v), add(v, u); }
void dfs1(int u, int fath, int dep)
{
dis1[u] = dep;
for (int i = head[u];i;i = edge[i].nxt)
{
int v = edge[i].to;
if (v != fath)
dfs1(v, u, dep + 1);
}
}
void dfs2(int u, int fath, int dep)
{
dis2[u] = dep;
for (int i = head[u];i;i = edge[i].nxt)
{
int v = edge[i].to;
if (v != fath)
dfs2(v, u, dep + 1);
}
}
int main(void)
{
n = read(), m = read(), d = read();
for (int i = 1;i <= m;i++)
evil[i] = read();
for (int i = 1;i < n;i++)
{
int u = read(), v = read();
addedge(u, v);
}
dfs1(1, 0, 0);
for (int i = 1;i <= m;i++)
if (dis1[evil[i]] > dis1[tmp]) tmp = evil[i];
dfs1(tmp, 0, 0);tmp = 0;
for (int i = 1;i <= m;i++)
if (dis1[evil[i]] > dis1[tmp]) tmp = evil[i];
dfs2(tmp, 0, 0);
for (int i = 1;i <= n;i++)
if (dis1[i] <= d && dis2[i] <= d) ans++;
printf("%d\n", ans);
return 0;
}