CF1039D You Are Given a Tree

You Are Given a Tree

Luogu CF1039D

Codeforces CF1039D

题面翻译

有一棵 \(n\) 个节点的树。

其中一个简单路径的集合被称为 \(k\) 合法当且仅当:

树的每个节点至多属于其中一条路径,且每条路径恰好包含 \(k\) 个点。

对于 \(k\in [1,n]\),求出 \(k\) 合法路径集合的最多路径数
即:设 \(k\) 合法路径集合为 \(S\),求最大的 \(|S|\)

\(n \leq 10^5\)

题目描述

A tree is an undirected graph with exactly one simple path between each pair of vertices. We call a set of simple paths $ k $ -valid if each vertex of the tree belongs to no more than one of these paths (including endpoints) and each path consists of exactly $ k $ vertices.

You are given a tree with $ n $ vertices. For each $ k $ from $ 1 $ to $ n $ inclusive find what is the maximum possible size of a $ k $ -valid set of simple paths.

输入格式

The first line of the input contains a single integer $ n $ ( $ 2 \le n \le 100,000 $ ) — the number of vertices in the tree.

Then following $ n - 1 $ lines describe the tree, each of them contains two integers $ v $ , $ u $ ( $ 1 \le v, u \le n $ ) — endpoints of the corresponding edge.

It is guaranteed, that the given graph is a tree.

输出格式

Output $ n $ numbers, the $ i $ -th of which is the maximum possible number of paths in an $ i $ -valid set of paths.

样例 #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

学习根号分治的好题。

首先可以知道的是,确定 \(k\) 过后,答案最多是 \(\dfrac{n}{k}\),根据整除分块的思想可以得知这个答案的值只会有 \(\mathcal O(\sqrt n)\) 种取值方法。并且随着 \(k\) 的增大答案在不停减小。

根据这些,可以得知最后的结果应该是类似于整除分块一样的形式,递减并且相等的答案一定是连续的。

会发现,这个答案序列的前半部分的变化幅度很大,后半部分的变化幅度很小,因此可以设置一个阈值 \(siz\),小于等于 \(siz\) 的部分暴力做,大于的部分暴力做完二分找到答案连续段的右端点。这道题就完成了大半了。

考虑已知 \(k\) 如何计算答案。可以从下往上贪心,如果当前链的长度已经大于等于了 \(k\),那么就将答案加一。具体写法可以参考代码进行理解。

// 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;
}
posted @ 2023-01-16 17:39  Hanx16Msgr  阅读(29)  评论(0编辑  收藏  举报