CF1039D You Are Given a Tree
You Are Given a Tree
题面翻译
有一棵
其中一个简单路径的集合被称为
树的每个节点至多属于其中一条路径,且每条路径恰好包含
对于
即:设
题目描述
A tree is an undirected graph with exactly one simple path between each pair of vertices. We call a set of simple paths
You are given a tree with
输入格式
The first line of the input contains a single integer
Then following
It is guaranteed, that the given graph is a tree.
输出格式
Output
样例 #1
样例输入 #1
7
1 2
2 3
3 4
4 5
5 6
6 7
样例输出 #1
7
3
2
1
1
1
1
样例 #2
样例输入 #2
6
1 2
2 3
2 4
1 5
5 6
样例输出 #2
6
2
2
1
1
0
提示
One way to achieve the optimal number of paths for the second sample is illustrated in the following picture:
Solution
学习根号分治的好题。
首先可以知道的是,确定
根据这些,可以得知最后的结果应该是类似于整除分块一样的形式,递减并且相等的答案一定是连续的。
会发现,这个答案序列的前半部分的变化幅度很大,后半部分的变化幅度很小,因此可以设置一个阈值
考虑已知
// Problem: You Are Given a Tree
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1039D
// Memory Limit: 500 MB
// Time Limit: 7000 ms
// Author: Hanx16QwQ
#include<bits/stdc++.h>
using namespace std;
namespace Hanx16qwq {
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf;
template<class T> inline void read(T &x) {
x = 0; T flag = 1; char b = getchar();
while (!isdigit(b)) {flag = b == '-' ? -1 : 1; b = getchar();}
while (isdigit(b)) {x = x * 10 + b - 48; b = getchar();}
x *= flag;
}
template<class T, typename... Args> inline void read(T &x, Args&... args) {
read(x), read(args...);
}
template<class T> inline void write(T x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template<class T> inline void writewith(T x, char c) {
write(x), putchar(c);
}
const int _SIZE = 1e5;
int n;
struct EDGE {
int nxt, to;
}edge[(_SIZE << 1) + 5];
int tot, head[_SIZE + 5];
void AddEdge(int x, int y) {
edge[++tot] = {head[x], y};
head[x] = tot;
}
int dfn[_SIZE + 5], fa[_SIZE + 5], cnt;
int order[_SIZE + 5];
void Dfs(int x, int F) {
dfn[x] = ++cnt, order[cnt] = x, fa[x] = F;
for (int i = head[x]; i; i = edge[i].nxt) {
int twd = edge[i].to;
if (twd == F) continue;
Dfs(twd, x);
}
}
int fm[_SIZE + 5], fs[_SIZE + 5];
int Solve(int k) {
memset(fm, 0, sizeof fm);
memset(fs, 0, sizeof fs);
int res = 0;
for (int i = n; i; --i) {
int x = order[i], y = fa[x];
if (fm[x] + fs[x] + 1 >= k) {
fm[x] = fs[x] = 0;
++res;
} else {
if (fm[y] < fm[x] + 1)
fs[y] = fm[y], fm[y] = fm[x] + 1;
else if (fs[y] < fm[x] + 1)
fs[y] = fm[x] + 1;
}
}
return res;
}
void main() {
read(n);
int siz = sqrt(n * __lg(n));
for (int i = 1, x, y; i < n; ++i) {
read(x, y);
AddEdge(x, y), AddEdge(y, x);
}
Dfs(1, 0);
for (int k = 1; k <= n; ++k) {
if (k <= siz) writewith(Solve(k), '\n');
else {
int ans = Solve(k);
int l = k, r = n;
while (l <= r) {
int mid = (l + r) >> 1;
if (Solve(mid) != ans) r = mid - 1;
else l = mid + 1;
}
for (int i = k; i <= r; ++i)
writewith(ans, '\n');
k = r;
}
}
}
}
signed main() {
Hanx16qwq::main();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步