【Codeforces 533A】Berland Miners

题目链接

【Codeforces 533A】Berland Miners

做法

先判定不修改是否合法。对于一个点 $ i $ ,它的价值为它到根节点 $ 1 $ 的路径上的最小值 $ mn[i] $(存在修改可能为次小值 $ nxt[i] $ ),将所有人的高度和 $ mn[i] $ 排序,山洞权值为 $ 1 $ ,人的权值为 $ -1 $ ,若任意前缀和都不小于 $ 0 $ ,则无需修改。
如果存在修改,那么一定要使得最后一个前缀和小于 $ 0 $ 的位置不小于 $ 0 $ ,这样处理就不需要二分了。
记录有多少个节点是取了 $ i $ 节点的 $ h_i $ , $ 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
#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define fst first
#define snd second
using namespace std;
typedef pair<int, int> pii;
typedef multiset<pii>::iterator IT;
const int INF = 0x3f3f3f3f;
const int N = 1000010;
int n, h[N], m, a[N], lb[N], ans = INF, pos;
vector<int> e[N], chs[N];
int mn[N], nxt[N];
multiset<pii> st;
struct P { int mn, lz; }; P tr[N * 4];

inline int Min(const int &x, const int &y) { return x < y ? x : y; }
inline bool cmp(const pii &x, const pii &y) { return x.fst > y.fst; }
void dfs(int u, int ff) {
st.insert(mp(h[u], u)); IT it = st.begin();
mn[u] = it->fst, chs[it->snd].pb(u);
++it;
if(it != st.end()) nxt[u] = it->fst; else nxt[u] = INF;
for(auto v : e[u]) if(v != ff) dfs(v, u);
st.erase(st.find(mp(h[u], u)));
}
inline void pushup(int u) { tr[u].mn = Min(tr[u * 2].mn, tr[u * 2 + 1].mn); }
void build(int u, int l, int r) {
if(l >= r) { tr[u].mn = -(m - l + 1); return ; }
int mid = (l + r) >> 1;
build(u * 2, l, mid), build(u * 2 + 1, mid + 1, r);
pushup(u);
}
inline void pushtag(int u, int w) { tr[u].mn += w, tr[u].lz += w; }
void pushdown(int u) {
if(tr[u].lz) {
pushtag(u * 2, tr[u].lz), pushtag(u * 2 + 1, tr[u].lz);
tr[u].lz = 0;
}
}
void mdy(int u, int l, int r, int L, int R, int w) {
if(L > R) return ;
if(l == L && r == R) { pushtag(u, w); return ; }
int mid = (l + r) >> 1; pushdown(u);
if(R <= mid) mdy(u * 2, l, mid, L, R, w);
else if(L > mid) mdy(u * 2 + 1, mid + 1, r, L, R, w);
else {
mdy(u * 2, l, mid, L, mid, w);
mdy(u * 2 + 1, mid + 1, r, mid + 1, R, w);
}
pushup(u);
}
int qry(int u, int l, int r, int x) {
if(l >= r) return tr[u].mn;
int mid = (l + r) >> 1; pushdown(u);
return x <= mid ? qry(u * 2, l, mid, x) : qry(u * 2 + 1, mid + 1, r, x);
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &h[i]);
for(int i = 1, x, y; i < n; i++)
scanf("%d%d", &x, &y), e[x].pb(y), e[y].pb(x);
scanf("%d", &m);
for(int i = 1; i <= m; i++) scanf("%d", &a[i]);
sort(a + 1, a + m + 1), dfs(1, 0), build(1, 1, m);
for(int i = 1; i <= n; i++) {
lb[i] = upper_bound(a + 1, a + m + 1, mn[i]) - a - 1;
mdy(1, 1, m, 1, lb[i], 1);
}
if(tr[1].mn >= 0) { puts("0"); return 0; }
for(pos = m; pos >= 1; pos--) if(qry(1, 1, m, pos) < 0) break;
for(int i = 1; i <= n; i++) {
if(lb[i] >= pos || nxt[i] < a[pos] || chs[i].size() < -tr[1].mn)
continue;
for(auto v : chs[i]) {
int x = Min(a[pos], nxt[v]);
x = upper_bound(a + 1, a + m + 1, x) - a - 1;
mdy(1, 1, m, lb[v] + 1, x, 1);
}
if(tr[1].mn >= 0) ans = Min(ans, a[pos] - h[i]);
for(auto v : chs[i]) {
int x = Min(a[pos], nxt[v]);
x = upper_bound(a + 1, a + m + 1, x) - a - 1;
mdy(1, 1, m, lb[v] + 1, x, -1);
}
}
if(ans == INF) puts("-1"); else printf("%d\n", ans);
return 0;
}