「CF1039D」You Are Given a Tree
根号分治,最近遇到挺多的。
\texttt {Solution}
考虑对于一个固定的
可以贪心,如果子树中过根的最长链的长度
如果已知
如果暴力跑
所以容易想到根号分治,不妨设一个临界值
#include <cstdio>
#include <vector>
#define LL long long
#define uLL unsigned LL
namespace Read {
static const int buf_size = 1 << 12;
static const bool use_fread = true;
static unsigned char buf[buf_size];
static int buf_len, buf_pos;
bool isEOF() {
if (buf_pos == buf_len) {
buf_pos = 0; buf_len = fread(buf, 1, buf_size, stdin);
if (buf_pos == buf_len) return true;
}
return false;
}
char readChar() {
if (!use_fread) return getchar();
return isEOF() ? EOF : buf[buf_pos++];
}
LL rint() {
LL x = 0, Fx = 1; char c = readChar();
while (c < '0' || c > '9') { Fx ^= (c == '-'); c = readChar(); }
while ('0' <= c && c <= '9') { x = (x << 3) + (x << 1) + (c ^ 48); c = readChar(); }
return Fx ? x : -x;
}
template <typename T>
void read(T &x) {
x = rint();
}
template <typename T, typename... Ts>
void read(T &x, Ts &...rest) {
read(x);
read(rest...);
}
} using namespace Read;
namespace Math {
LL Max(LL u, LL v) { return (u > v) ? u : v; }
LL Min(LL u, LL v) { return (u < v) ? u : v; }
} using namespace Math;
const int MAX_n = 1e5;
const int mx = 1289;
int n, Time;
int dp[MAX_n + 5];
int id[MAX_n + 5];
int dfn[MAX_n + 5];
int res[MAX_n + 5];
std::vector<int> G[MAX_n + 5];
void add_edge(int u, int v) {
G[u].push_back(v);
G[v].push_back(u);
}
void dfs(int u, int Fu) {
id[dfn[u] = ++Time] = u;
for (auto v : G[u])
if (v != Fu) dfs(v, u);
}
int chk(int k) {
int ans = 0;
for (int i = n; i >= 1; i--) {
int u = id[i];
int fir = 0, sec = 0;
for (auto v : G[u]) {
if (dfn[v] >= dfn[u]) {
if (dp[v] > fir) sec = fir, fir = dp[v];
else if (dp[v] > sec) sec = dp[v];
}
}
dp[u] = (((fir + sec + 1) >= k) ? 0 : (fir + 1));
ans += ((fir + sec + 1) >= k);
}
return ans;
}
int main() {
#ifdef LOCAL
freopen("DATA.in", "r", stdin);
// freopen("DATA.out", "w", stdout);
#endif
read(n);
for (int i = 1, u, v; i < n; i++)
read(u, v), add_edge(u, v);
dfs(1, 0);
for (int k = 1; k <= mx && k <= n; k++)
res[k] = chk(k);
for (int s = 1; s <= n; s++) {
int L = 1, R = n / s;
if (R <= mx) break;
while (L < R) {
int Mid = (L + R + 1) >> 1;
if (chk(Mid) >= s) L = Mid;
else R = Mid - 1;
}
res[L] = Max(res[L], s);
}
for (int i = n; i >= 1; i--)
res[i] = Max(res[i], res[i + 1]);
for (int i = 1; i <= n; i++)
printf("%d\n", res[i]);
return 0;
}