题解:P17834 [CSP-S 2026] 研发基地 / hub

深刻。

考虑 \(k=1\) 的时候取直径中点最优,进一步不难发现连通块必然包含直径中点。

考虑二分 \(mid\),求出令 \(\max d(i)\leq mid\) 的最少点数。枚举断边,对两个连通块分别求出在内部选一个连通块覆盖所有点的最少点数。对于一个连通块,以直径中点为根,对于每个深度为 \(d>mid\) 的点,其深度为 \(d-mid\) 的祖先必须被选中,自底向上求出必须被选中的点数即可。时间复杂度为 \(\mathcal{O}(n^2\log{n})\),考场上的思考就到此为止了。

考虑优化 check 的复杂度。每个连通块都求出以直径中点为根的信息看上去不太好做,考虑抛开这个结构直接去 DP。比较容易求出的是:\(f_u\) 表示强制选择点 \(u\) 覆盖 \(sub_u\) 的最少点数。令 \(h_u\) 表示子树高度,那么容易得到转移:

\[f_u=1+\sum_{v\in son_u\land h_v\geq mid}f_v \]

再来考虑如果不强制选择点 \(u\) 怎么做。观察到如果有至少两个儿子 \(v\) 满足 \(h_v\geq mid\),那么 \(u\) 是必选的,因此如果 \(u\) 可以不被选择,它至多只有一个儿子满足 \(h_v\geq mid\)。由此不难看出,不强制选择点 \(u\) 的方案,形如从 \(f_u\) 给出的方案中删去一条从 \(u\) 开始的链。

设计 \(g_u\) 表示这条链的最大长度。若 \(u\) 恰好有一个儿子 \(v\) 满足 \(h_v\geq mid\),则设 \(d=\max\limits_{w\in son_u\land w\neq v}\{h_w+1\}\),可以得到转移:

\[g_u=\min(g_v+1,mid-d) \]

否则 \(g_u=0\)。

这个状态就很方便换根了。对于每个 \(u\),我们求出 \(u\) 子树内/子树外的最大、次大的 \(h\) 和最大的 \(h\) 对应的节点,转移 \(g\) 的时候直接判断是否有 \(mx>mid\land smx\leq mid\) 就好了。

时间复杂度 \(\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 = 1e6 + 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 tid, tc, n, k, fa[MAXN];
int deg[MAXN], st[MAXN], ed[MAXN], T[MAXN << 1];
int f[MAXN], g[MAXN], g2[MAXN];
pii edges[MAXN];
vector<int> ord;

struct Info {
	int mx, mxp, smx;
} a[MAXN], b[MAXN];

bool check(int mid) {
	fill(f + 1, f + n + 1, 1);
	for (int u : ord | views::reverse) {
		g[u] = a[u].mx > mid && a[u].smx <= mid ? min(g[a[u].mxp] + 1, mid - a[u].smx) : 0;
		if (fa[u] && a[u].mx >= mid) f[fa[u]] += f[u];
	}
	if (f[1] - g[1] <= k) return true;

	for (int u : ord) {
		for (int _ = st[u]; _ < ed[u]; ++_) {
			int v = T[_];
			if (v == fa[u]) continue;
			int nf = f[u] - (a[v].mx >= mid ? f[v] : 0);
			g2[v] = b[v].mx > mid && b[v].smx <= mid ? min(b[v].mxp == fa[u] ? g2[u] + 1 : g[b[v].mxp] + 1, mid - b[v].smx) : 0;
			if (nf - g2[v] + f[v] - g[v] <= k) return true;
			if (b[v].mx >= mid) f[v] += nf;
		}
	}
	return false;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	cin >> tid >> tc;
	while (tc--) {
		cin >> n >> k;

		fill(deg + 1, deg + n + 1, 0);
		for (int i = 1; i < n; ++i) {
			int u, v;
			cin >> u >> v;
			edges[i] = {u, v};
			++deg[u];
			++deg[v];
		}

		st[1] = ed[1] = 0;
		for (int i = 1; i < n; ++i) st[i + 1] = ed[i + 1] = st[i] + deg[i];
		for (int i = 1; i < n; ++i) {
			auto [u, v] = edges[i];
			T[ed[u]++] = v;
			T[ed[v]++] = u;
		}

		ord.clear();
		ord.emplace_back(1);
		for (int i = 0; i < n; ++i) {
			int u = ord[i];
			for (int _ = st[u]; _ < ed[u]; ++_) {
				int v = T[_];
				if (v == fa[u]) continue;
				fa[v] = u;
				ord.emplace_back(v);
			}
		}

		int D = 0;
		fill(a + 1, a + n + 1, Info{0, 0, 0});
		for (int u : ord | views::reverse) {
			chkMax(D, a[u].mx + a[u].smx);
			if (u == 1) break;
			int p = fa[u];
			if (a[u].mx + 1 >= a[p].mx) {
				a[p].smx = a[p].mx;
				a[p].mx = a[u].mx + 1;
				a[p].mxp = u;
			} else {
				chkMax(a[p].smx, a[u].mx + 1);
			}
		}
		for (int u : ord) {
			array<pii, 3> h;
			for (int _ = st[u]; _ < ed[u]; ++_) {
				int v = T[_];
				pii val = {v == fa[u] ? b[u].mx + 1 : a[v].mx + 1, v};
				for (auto &c : h) {
					if (val > c) swap(val, c);
				}
			}
			for (int _ = st[u]; _ < ed[u]; ++_) {
				int v = T[_];
				if (v == fa[u]) continue;
				pii x = h[0], y = h[1];
				if (x.second == v) {
					x = h[1];
					y = h[2];
				} else if (y.second == v) {
					y = h[2];
				}
				b[v] = {x.first, x.second, y.first};
			}
		}

		int l = 0, r = D + 1 >> 1;
		while (l < r) {
			int mid = l + r >> 1;
			if (check(mid)) r = mid;
			else l = mid + 1;
		}
		cout << l << '\n';
	}
	return 0;
}
posted @ 2026-11-01 11:50  P2441M  阅读(80)  评论(0)    收藏  举报