Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P1084 [NOIP2012 提高组] 疫情控制

P1084 [NOIP2012 提高组] 疫情控制

单调性显然,考虑二分答案。

对于所有根节点的儿子记为 $q _ i$ ,对于所有军队记为 $p _ i$ ,考虑二分答案,一个 $q _ i$ 有两种情况:从其他 $q$ 转移来,从儿子来。先考虑第二种情况,考虑 DP ,$f _ i$ 表示是否合法,$g _ i$ 表示距离儿子中军队最近距离。 $f _ i$ 合法当且仅当所有儿子都合法或者 $g _ i \le mid$ 。

对于第二种情况,如果一个 $q _ i$ 中有多个军队,选择留下一个深度最大的,其他的考虑给其他 $q _ i$ ,对于没有军队的 $q _ i$ ,深度从大到小排序,选择第一个没有被选择的军队即可。

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <cstdio>
#include <vector>
#define eb emplace_back
#include <algorithm>
using namespace std;
template <class Type>
void read (Type &x)
{
char c;
bool flag = false;
while ((c = getchar()) < '0' || c > '9')
c == '-' && (flag = true);
x = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
x = (x << 1) + (x << 3) + c - '0';
flag && (x = ~x + 1);
}
template <class Type, class ...rest>
void read (Type &x, rest &...y) { read(x), read(y...); }
template <class Type>
void write (Type x)
{
x < 0 && (putchar('-'), x = ~x + 1);
x > 9 && (write(x / 10), 0);
putchar('0' + x % 10);
}
typedef long long L;
const L inf = 1e15;
const int N = 5e4 + 10;
L d[N], g[N];
bool f[N], vis[N];
int n, m, top[N], h[N], p[N];
struct Edge { int v, w; };
vector <Edge> e[N];
vector <int> q;
void dfs (int u, int fa, int &t)
{
top[u] = t;
for (Edge i : e[u]) if (i.v ^ fa)
{
d[i.v] = d[u] + i.w;
dfs(i.v, u, t);
}
}
void dfs (int u, int fa, L &mid)
{
if (f[u]) return void(g[u] = 0);
g[u] = inf;
if (e[u].size() == 1) return;
f[u] = true;
for (Edge i : e[u]) if (i.v ^ fa)
{
dfs(i.v, u, mid);
f[u] &= f[i.v];
g[u] = min(g[u], g[i.v] + i.w);
}
if (g[u] <= mid) f[u] = true;
}
bool check (L mid)
{
for (int i = 1; i <= n; ++i) f[i] = false;
for (int i = 1; i <= m; ++i) vis[i] = false;
for (int i = 1; i <= n; ++i) h[i] = 0;
int t = 0, cur = m;
for (int i = 1; i <= m; ++i)
if (d[p[i]] > mid) f[p[i]] = true, t = i;
else if (!h[top[p[i]]]) h[top[p[i]]] = i;
for (int i : q)
{
dfs(i, 1, mid);
if (f[i]) continue;
if (!h[i] || vis[h[i]])
{
while (cur > t && (vis[cur] || d[i] + d[p[cur]] > mid)) --cur;
if (cur > t) vis[cur] = true;
else { --cur; break; }
}
else vis[h[i]] = true;
}
return cur >= t;
}
int main ()
{
read(n);
for (int i = 1, a, b, c; i < n; ++i)
{
read(a, b, c);
e[a].eb((Edge){ b, c });
e[b].eb((Edge){ a, c });
}
read(m);
if (e[1].size() > m) return puts("-1"), 0;
for (Edge i : e[1])
d[i.v] = i.w, dfs(i.v, 1, i.v), q.eb(i.v);
for (int i = 1; i <= m; ++i) read(p[i]);
sort(p + 1, p + m + 1, [&](int a, int b) { return d[a] > d[b]; });
sort(q.begin(), q.end(), [&](int a, int b) { return d[a] > d[b]; });
L l = 0, r = inf;
while (l < r)
{
L mid = l + r >> 1;
check(mid) ? r = mid : l = mid + 1;
}
write(l);
return 0;
}