感觉CF的div2都变简单了。
可以很明显看出贪心,我们从下到上合并每一棵子树,对于一个点$x$所有的儿子$y$,我们把所有$dis_y$丢到一个$vector$里面排序,然后从小到大扫描每一条边,如果$dis_p + dis_{p +1} > K$的话,那么排序之后大于$p$的下标肯定都不行了,也就是说除了$1,2,3...,p$其他都需要建一个新的集合。
这样到最后还有一个集合没有被计算到答案中去,最后答案要$+1$
还有一个细节就是要选择一个非叶子结点做根搜索。
时间复杂度$O(nlogn)$。
Code:

#include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 1e6 + 5; int n, K, ans = 0, tot = 0, head[N], deg[N], dis[N]; vector <int> vec[N]; struct Edge { int to, nxt; } e[N << 1]; inline void add(int from, int to) { e[++tot].to = to; e[tot].nxt = head[from]; head[from] = tot; } inline void read(int &X) { X = 0; char ch = 0; int op = 1; for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } void dfs(int x, int fat) { if(deg[x] == 1) { dis[x] = 1; return; } for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(y == fat) continue; dfs(y, x); vec[x].push_back(dis[y]); } sort(vec[x].begin(), vec[x].end()); int pre = vec[x][0], pos = 1; for(; (unsigned)pos < vec[x].size() && pre + vec[x][pos] <= K; pre = vec[x][pos], ++pos); ans += vec[x].size() - pos, dis[x] = pre + 1; } int main() { read(n), read(K); for(int x, y, i = 1; i < n; i++) { read(x), read(y); add(x, y), add(y, x); deg[x]++, deg[y]++; } int root = 1; for(; root <= n; ++root) if(deg[root] > 1) break; dfs(root, 0); printf("%d ", ans + 1); return 0; }