好题一则:ARC-063 E - 木と整数
https://atcoder.jp/contests/arc063/tasks/arc063_c
2198 ELO 相当
给定 $N$ 个点的一棵树,有 $K$ 个点上有数字,构造一种数字填写法,使得所有相临的点数字相差刚好 $\pm 1$.
可以很容易看出有 (\text{dis}(u,v) < \text{abs}(u - v)) 无解,并且满足奇偶性.
如果每一个点扩张之后都可以扩展自己的值域,那么其扩展的范围就是 $[L - 1, R + 1]$.
如果两个值域在某个点相遇,考虑合并其即可,因为是取小.
树上 DP 即可,但是细节有些多.
void solve() {
LL(N);
V<V<ll>> E(N);
rep(i, N - 1) {
LL(u, v); -- u, -- v;
E[u].push(v);
E[v].push(u);
}
LL(K);
V<pll> D(N, {-INF, INF});
V<bool> vis(N, 0);
ll root;
rep(K) {
LL(v, P); -- v;
D[v] = {P, P};
vis[v] = true;
root = v;
}
auto meg = [&](int u, int v) -> bool { // fa, son
D[u].fst = max(D[u].fst, D[v].fst - 1);
D[u].snd = min(D[u].snd, D[v].snd + 1);
return D[u].fst <= D[u].snd;
};
auto dfs = [&](auto&&dfs, int u, int fa, int p) -> void {
if(vis[u]) {
if(D[u].fst % 2 != p) {
wt("No"); exit(0);
}
} else {
if(p == 1) { // INF = 1 << 60, 转成奇数所以 + - 1
D[u].fst ++;
D[u].snd --;
}
}
each(v, E[u]) if(v != fa) {
dfs(dfs, v, u, p ^ 1);
if(!meg(u, v)) {
wt("No"); exit(0);
}
}
};
dfs(dfs, root, -1, D[root].fst % 2);
debug(D); debug(root); debug(D[root]);
wt("Yes");
V<ll> ans(N, -1);
ans[root] = D[root].fst;
auto dfs1 = [&](auto&&dfs1, int u, int fa, int p) -> void {
each(v, E[u]) if(v != fa) {
if(p + 1 >= D[v].fst && p + 1 <= D[v].snd) {
ans[v] = p + 1;
dfs1(dfs1, v, u, p + 1);
} else {
ans[v] = p - 1;
dfs1(dfs1, v, u, p - 1);
}
}
};
dfs1(dfs1, root, -1, ans[root]);
each(x, ans) wt(x);
debug(ans);
}