E1题目链接:https://codeforces.com/contest/1611/problem/E1
E2题目链接:https://codeforces.com/contest/1611/problem/E2
分析
我们定义一个点叫做安全点,即走到这个点上即可到达安全的叶子节点(不会被朋友逮到);朋友初始站的点叫朋友点,否则叫非朋友点; d e e p [ i ] deep[i] deep[i]表示第 i i i号点的深度, m d [ i ] md[i] md[i]表示在第 i i i号点下面距离 i i i最近的朋友点的深度。
很明显若一个点是叶子节点,同时它是非朋友点,那么它就是一个安全点;同样很明显若一个点是朋友点,那么它以及它下方的点一定不是安全点。我们可以将安全点的状态转移向它的父亲点进行转移。
如何确定一个非叶子非朋友节点
i
i
i是否是安全点呢?若
i
i
i的孩子节点中有安全点,同时
在第
i
i
i号点下面距离
i
i
i最近的朋友点的距离比该点到
1
1
1号点的距离大(
d
e
e
p
[
i
]
−
1
<
m
d
[
i
]
−
d
e
e
p
[
i
]
deep[i]-1<md[i]-deep[i]
deep[i]−1<md[i]−deep[i]),也就是朋友抓不到Vlad,那么
i
i
i号点就是一个安全点。
对于E1,只要判断最终
1
1
1号点是不是安全点即可。
对于E2,如果
1
1
1号点不是安全点,那么想一下,我们如果将所有的朋友点都尽量往上移动,移到最极限的位置(即刚好和Vlad碰到),然后dfs搜索到朋友点就
a
n
s
+
1
ans+1
ans+1,并且不必再遍历下去。我们可以利用
m
d
md
md数组来实现这个过程,即搜索到一个点
i
i
i满足
d
e
e
p
[
i
]
−
1
≥
m
d
[
i
]
−
d
e
e
p
[
i
]
deep[i] - 1 \geq md[i] - deep[i]
deep[i]−1≥md[i]−deep[i],就
a
n
s
+
1
ans+1
ans+1,并且不必再遍历下去。
具体看代码
代码
E1
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define fi first
#define se second
#define lson (k << 1)
#define rson (k << 1 | 1)
const ll LINF = 1e18;
const int INF = 1e9 + 7;
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const ll P = 1e9 + 7;
const double eps = 1e-7;
int n, k;
int f[N], safe[N], deep[N], md[N];
vector<int> g[N];
void dfs(int u, int fa)
{
deep[u] = deep[fa] + 1;
if(f[u])
{
md[u] = min(md[u], deep[u]);
return;
}
if(g[u].size() == 1 && u != 1)
{
safe[u] = 1;
return;
}
int ifsafe = 0, mn = INF;
for(int i=0,v;i<g[u].size();i++)
{
v = g[u][i];
if(v == fa) continue;
dfs(v, u);
md[u] = min(md[u], md[v]);
if(safe[v]) ifsafe = 1;
}
if(ifsafe && deep[u] - 1 < md[u] - deep[u]) safe[u] = 1;
}
int main()
{
int T = 1;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&k);
for(int i=0;i<=n;i++) g[i].clear(), f[i] = deep[i] = safe[i] = 0, md[i] = INF;
for(int i=1,x;i<=k;i++)
{
scanf("%d",&x);
f[x] = 1;
}
for(int i=1,u,v;i<n;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
if(safe[1]) printf("YES\n");
else printf("NO\n");
}
return 0;
}
E2
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define fi first
#define se second
#define lson (k << 1)
#define rson (k << 1 | 1)
const ll LINF = 1e18;
const int INF = 1e9 + 7;
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const ll P = 1e9 + 7;
const double eps = 1e-7;
int n, k, ans;
int f[N], safe[N], deep[N], md[N];
vector<int> g[N];
void dfs(int u, int fa)
{
deep[u] = deep[fa] + 1;
if(f[u])
{
md[u] = min(md[u], deep[u]);
return;
}
if(g[u].size() == 1 && u != 1)
{
safe[u] = 1;
return;
}
int ifsafe = 0, mn = INF;
for(int i=0,v;i<g[u].size();i++)
{
v = g[u][i];
if(v == fa) continue;
dfs(v, u);
md[u] = min(md[u], md[v]);
if(safe[v]) ifsafe = 1;
}
if(ifsafe && deep[u] - 1 < md[u] - deep[u]) safe[u] = 1;
}
void dfs2(int u, int fa)
{
if(deep[u] - 1 >= md[u] - deep[u])
{
ans++;
return;
}
for(int i=0,v;i<g[u].size();i++)
{
v = g[u][i];
if(v == fa) continue;
dfs2(v, u);
}
}
int main()
{
int T = 1;
scanf("%d",&T);
while(T--)
{
ans = 0;
scanf("%d%d",&n,&k);
for(int i=0;i<=n;i++) g[i].clear(), f[i] = deep[i] = safe[i] = 0, md[i] = INF;
for(int i=1,x;i<=k;i++)
{
scanf("%d",&x);
f[x] = 1;
}
for(int i=1,u,v;i<n;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
if(safe[1]) printf("-1\n");
else
{
dfs2(1, 0);
printf("%d\n",ans);
}
}
return 0;
}