题解:ARC152F Attraction on Tree
尝试给出一个不太一样的做法。
显然若 \(\operatorname{dis}(1,n)\) 与 \(n\) 奇偶性不同则无解,下面设 \(m=\dfrac{n-\operatorname{dis}(1,n)}{2}\)。
把 \(n\) 视作树根。设 \(vis_u=[u\in\operatorname{path}(1,n)]\),对于一个非根点 \(u\),设从 \(fa_u\) 走到 \(u\) 的次数为 \(x_u\),则从 \(u\) 走到 \(fa_u\) 的次数就是 \(x_u+vis_u\),于是 \(\sum x_u=m\)。
最终经过的顶点形成一个包含 \(\operatorname{path}(1,n)\) 的连通块,其中不在路径上的点 \(u\) 要求 \(x_u\geq 1\)。对于任意一组 \(x\),取一个 \(1\) 到 \(n\) 的欧拉路径即可得到合法的移动方案,问题在于判定能否分配不同的操作点。
使用左部点带流量的 Hall 定理来刻画,左部点为 \(2(n-1)\) 类移动,右部点为 \(n\) 个操作点,对于每一类移动,向对应的操作点连边。具体来说,若左部点 \(p\) 表示从 \(fa_u\) 走到 \(u\),则给 \(p\) 传入 \(x_u\) 的流量,把 \(p\) 连向 \(sub_u\) 内的右部点;若 \(p\) 表示从 \(u\) 走到 \(fa_u\),则给 \(p\) 传入 \(x_u+vis_u\) 的流量,把 \(p\) 连向 \(sub_u\) 外的右部点。观察到这个二分图性质很好:对于任意两个左部点 \(p,q\),若 \(N(p)\cap N(q)\neq\varnothing\) 且 \(N(p)\) 与 \(N(q)\) 互不包含,则必然有 \(N(p)\cup N(q)=[n]\)。因此我们实际上只需要对于每个左部点 \(p\),判断是否有 \(\sum\limits_{N(q)\subseteq N(p)}f_q\leq |N(p)|\),其中 \(f_q\) 表示左部点 \(q\) 的流量。
设 \(S_u=\sum\limits_{v\in sub_u}x_v\)。若 \(p\) 表示从 \(fa_u\) 走到 \(u\),则判定条件为 \(S_u\leq sz_u\);若 \(p\) 表示从 \(u\) 走到 \(fa_u\),则 \(u\) 的后代都没有贡献,\(u\) 和 \(u\) 的祖先贡献 \(x_v+vis_v\),其他点贡献 \(x_v\),因此判定条件为 \(m-\sum\limits_{fa_v=u}S_v+c_u\leq n-sz_u\),其中 \(c_u\) 表示 \(\operatorname{path}(1,u)\) 和 \(\operatorname{path}(1,n)\) 的边交集大小。
整理一下,设 \(L_u=m+c_u+sz_u-n\),那么一组 \(x\) 合法的判定条件就是 \(S_u\leq sz_u\) 且 \(\sum\limits_{fa_v=u}S_v\geq L_u\)。
做一些观察,对于一种合法方案,猜测 \(S_u\) 的取值范围是一个区间 \([low_u,sz_u]\)。考虑直接归纳,固定 \(sub_u\) 内经过的点,对经过的儿子节点的 \(low,sz\) 分别求和得到 \(X,Y\),则 \(\sum\limits_{fa_v=u}S_v\) 可以取到 \([X,Y]\) 内的任意整数。我们要求 \(x_u\geq 1-vis_u\),因此取 \(low_u=\max(X,L_u)+(1-vis_u)\),则 \(S_u\) 可以取到 \([low_u,sz_u]\) 内的任意整数。这个性质启发我们只需记录子树内的 \(low_u\) 和最少经过点数。
考虑贪心,用 \(low_u\) 表示上述下界,\(mn_u\) 表示子树内的最少经过点数。满足 \(vis_v=1\) 或者 \(L_v>0\) 的儿子节点必须被经过,因此先扫一遍必须经过的儿子 \(v\),令:
再来考虑可选的儿子 \(v\)。考察 \(v\) 的后代 \(w\),由于 \(vis_v=0\land L_v\leq 0\),此时有 \(c_w=c_v\),也就是说 \(L_w\leq L_v\leq 0\),于是我们不经过的 \(w\) 的后代也不影响合法性!因此可选儿子 \(v\) 的作用就是耗费一个点,提供一个取值区间 \([1,sz_v]\)。于是我们将可选儿子按 \(sz_v\) 降序从大到小扫,若 \(R<L_u\) 就令
最后再令 \(low_u\gets\max(low_u,L_u)+(1-vis_u)\) 即可。不难发现这种策略同时最小化了 \(low_u\) 和 \(mn_u\),正确性是有保证的。
根节点 \(n\) 需要单独处理,要求 \(\sum\limits_{fa_v=n}S_v=m\),检查 \(low_n\leq m\leq R\) 即可。
时间复杂度 \(\mathcal{O}(n\log{n})\)。
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using i128 = __int128;
using ui = unsigned int;
using ull = unsigned long long;
using u128 = unsigned __int128;
using ld = long double;
using pii = pair<int, int>;
const int MAXN = 2e5 + 5;
template<typename T> T lowbit(T x) { return x & -x; }
template<typename T> void chkMin(T &x, T y) { x = y < x ? y : x; }
template<typename T> void chkMax(T &x, T y) { x = x < y ? y : x; }
constexpr int lg2(ll x) { return 63 ^ __builtin_clzll(x); }
constexpr ll bitCeil(ll x) { return x == 1 ? 1ll : 1ll << lg2(x - 1) + 1; }
int n, m, fa[MAXN], dep[MAXN], sz[MAXN];
int c[MAXN], L[MAXN];
int low[MAXN], mn[MAXN];
bool vis[MAXN];
vector<int> T[MAXN];
void dfs1(int u) {
sz[u] = 1;
for (int v : T[u]) {
if (v == fa[u]) continue;
fa[v] = u;
dep[v] = dep[u] + 1;
dfs1(v);
sz[u] += sz[v];
}
}
int dfs2(int u) {
c[u] = vis[u] ? dep[u] : c[fa[u]];
L[u] = m + c[u] + sz[u] - n;
mn[u] = 1;
int hi = 0;
vector<int> vec;
for (int v : T[u]) {
if (v == fa[u]) continue;
if (dfs2(v) == -1) return -1;
if (vis[v] || L[v] > 0) {
low[u] += low[v];
hi += sz[v];
mn[u] += mn[v];
} else {
vec.emplace_back(sz[v]);
}
}
sort(vec.begin(), vec.end(), greater<>());
for (int s : vec) {
if (hi >= L[u]) break;
++low[u];
hi += s;
++mn[u];
}
if (hi < L[u]) return -1;
if (u == n) return low[u] <= m ? mn[u] : -1;
low[u] = max(low[u], L[u]) + !vis[u];
return mn[u] <= sz[u] ? 1 : -1;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i < n; ++i) {
int u, v;
cin >> u >> v;
T[u].emplace_back(v);
T[v].emplace_back(u);
}
dfs1(n);
if (n - dep[1] & 1) {
cout << "-1";
return 0;
}
m = n - dep[1] >> 1;
for (int p = 1; p; p = fa[p]) vis[p] = true;
cout << dfs2(n);
return 0;
}

浙公网安备 33010602011771号