题目大意
给你一棵树, n n n 个节点。你需要给每个节点染色,使得任意颜色相同的节点之间的路径上的点颜色也与前面两个点相同。
c n t i cnt_i cnti 表示颜色为 i i i 的节点数,找到 min c n t i \min cnt_i mincnti 的最大值。
简要分析
先不考虑,根不固定的情况,强制钦定 r = 1 r = 1 r=1,这里 r r r 指根节点。
我们发现答案通过二分可以转化成判定性问题,即能否将树划分成若干条自底向上目长度至少为 k k k 的链。
设 d e p u dep_u depu 表示,自底向上的到达 u u u 的最短长度, m i n x minx minx 表示么 x x x 的儿子中 d e p v dep_v depv 的最小值。
显然对于叶子有, d e p w = 1 dep_w=1 depw=1,而对于非时子节点,显然有转移 d e p w = m i n x + 1 dep_w=minx +1 depw=minx+1。
对于不合法的情况, u u u 存在两个儿子,他们的 d e p w dep_w depw 都要小于 k k k,因为 u u u 只能和一个儿子往上拼接,两个就不行了,这个记为情況 1 1 1。
最终只需要判断一下 d e p 1 dep_1 dep1, 是否不小于 k k k 即可,这个记为情况 2 2 2。
然后就是, r r r 不固定的情况,当然,假设说 r = 1 r = 1 r=1 可行那么我们就直接输出了。
如果情况 1 1 1 不合法,子树以外的点作为根是不可能的,因为这个子树的本身结构是不变的,所以我们就需要将 m i n x minx minx 对应的节点 v v v 变成根。
因为这种情况不合法一定是说明了这个点到 u u u 距离是小于 k k k 的,而肯定还有一个 v ’ v’ v’ 到 u u u 的距离是小于 v v v 的,所以我们本质上是把 v v v 到 v ’ v’ v’ 的路径涂成一种颜色。
如果情况 2 2 2 不合法,那么我们同理,也是找 m i n x minx minx 就行了。
总时间复杂度 O ( n ) O(n) O(n)。
代码实现
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
using namespace std;
typedef long long ll;
const ll maxn = 2e5 + 7;
const ll INF = 1e18 + 7, MOD = 998244353;
inline ll read() {
char cCc;
ll xXx = 0, wWw = 1;
while (cCc < '0' || cCc > '9')
(cCc == '-') && (wWw = -wWw), cCc = getchar();
while (cCc >= '0' && cCc <= '9')
xXx = (xXx << 1) + (xXx << 3) + (cCc ^ '0'), cCc = getchar();
xXx *= wWw;
return xXx;
}
inline void write(ll xXx) {
if (xXx < 0)
putchar('-'), xXx = -xXx;
if (xXx > 9)
write(xXx / 10);
putchar(xXx % 10 + '0');
}
ll n, tx, ty, dep[maxn], minnode[maxn];
vector<ll> G[maxn];
bool dfs(ll u, ll fa, ll k) {
ll x = 0, y = 0, miny = INF, minx = INF;
for (auto v : G[u]) {
if (v == fa)continue;
if (!dfs(v, u, k))return false;
if (dep[v] <= minx)y = x, miny = minx, x = minnode[v], minx = dep[v];
else if (dep[v] <= miny)y = minnode[v], miny = dep[v];
}
if (miny < k) {
tx = x, ty = y;
return false;
}
if (x == 0)dep[u] = 1, minnode[u] = u;
else dep[u] = minx + 1, minnode[u] = x;
if (!fa) {
if (dep[u] < k)tx = minnode[u], ty = 1;
return dep[u] >= k;
}
return true;
}
bool check(ll k) {
if (dfs(1, 0, k)) return true;
else if (dfs(tx, 0, k) || dfs(ty, 0, k))return true;
return false;
}
void solve() {
n = read();
for (ll i = 1; i < n; i++) {
ll u = read(), v = read();
G[u].push_back(v);
G[v].push_back(u);
}
ll l = 0, r = n, ans = 0;
while (l <= r) {
ll mid = (l + r) >> 1;
if (check(mid))
ans = mid, l = mid + 1;
else r = mid - 1;
}
cout << ans << '\n';
for (ll i = 1; i <= n; i++)G[i].clear();
}
signed main() {
// freopen("code.in","r",stdin);
// freopen("code.out","w",stdout);
ll T = read();
while (T--)solve();
return 0;
}