代码源周作业44 题解

CF2167E

二分答案,之后做法就很多了,其一是考虑每个点满足答案的是一段前缀 \([0, a_i - mid]\) 和一段后缀 \([a_i + mid, x]\),直接并的交就能得到答案了,但是细节比较多。所以考虑直接排序 \(a\),那么取所有 \([a_{i-1}+mid,a_i-mid]\) 的并即可。

CF2167F

考虑换一下统计贡献的方式,我们对每个点 \(x\) 统计有多少个点 \(u\),满足以 \(u\) 为根时 \(x\) 可以作为 LCA 被获取到,显然想让 \(x\) 为 LCA 最好的方式就是直接取 \(x\),然后再在 \(x\) 的子树中取 \(k-1\) 个点,换言之只要满足当 \(u\) 为根时,\(sz_x \ge k\) 即可。基于这个想法,我们先跑出以 \(1\) 为根时所有点的子树大小,再考虑换根时 \(x\) 的子树又变成了什么样呢。手玩可以发现,当取 \(x\) 外的点子树为根时,\(x\) 的子树大小不变;当取 \(x\) 子树内的点为根时,\(x\) 的子树大小变为 \(n\) 减去所在子树大小,那么我们直接统计即可。

// 如果命运对你缄默, 那就活给他看。
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast", "inline", "-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
typedef long long LL; 
// #define int LL
const int maxn = 2e5 + 10;
int n, k, sz[maxn];
vector<int>e[maxn];
LL ans = 0; 
inline void dfs(int u, int pa) {
	sz[u] = 1;
	for(int v : e[u]) 
		if(v != pa) dfs(v, u), sz[u] += sz[v];
	if(sz[u] >= k) ans += n - sz[u];
	for(int v : e[u])
		if(v != pa) {
			if(n - sz[v] >= k) ans += sz[v]; 
		}
}
inline void clear() {
	for(int i = 1; i <= n; ++ i) e[i].clear(); 
}
inline void solve() {
	cin >> n >> k, ans = n;
	for(int i = 1; i < n; ++ i) {
		int u, v;
		cin >> u >> v;
		e[u].emplace_back(v);
		e[v].emplace_back(u); 
	}
	dfs(1, 0);
	cout << ans << '\n'; 
}
signed main() {
	// freopen(".in", "r", stdin);
	// freopen(".out", "w", stdout);
	ios :: sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while(T--) clear(), solve();
	return 0;
}
posted @ 2025-11-17 11:00  Rainsheep  阅读(0)  评论(0)    收藏  举报