代码源周作业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;
}

浙公网安备 33010602011771号