「CF1918F」Caterpillar on a Tree
思路
口胡一个早读胡出来的……感觉 pyt 讲得不是很透。
为了使得操作同质化,不难首先想到:将
想象一下我们在树上行走的过程,肯定是一个叶子走完了就去下一个(这样也能保证每个点都经过)。这样一定每条边经过
考虑传送门带来的影响。首先是使用它的位置:一定是到了叶子节点用。
又,什么时候使用?发现对于一棵子树
推导一下(这里假设
如果使用传送门,那么我们下一步肯定也是要走到父亲的(但是从根节点走),所以代价是
两者相减就得到:
而因为我们是对每个节点都计算了
实现细节
-
可能会出现一个叶子重复使用传送门的情况,我们只需要记录一个 vis 数组即可。
-
注意 1 节点我们不能统计
b_x 进行操作,因为它没有父亲,无法按照这种算法计算。
#include <bits/stdc++.h>
#define pb push_back
#define int long long
using namespace std;
const int N = 5e5 + 5; int read();
int n, k, maxn[N], dep[N], b[N], ans;
bool vis[N]; vector <int> G[N];
struct node {
int id, x;
friend bool operator < (node a, node b) { return a.x > b.x; }
} a[N];
void dfs(int x, int fa) {
maxn[x] = dep[x] = dep[fa] + 1; b[x] = x;
for(int i = 0;i < G[x].size(); ++i) {
int to = G[x][i];
dfs(to, x);
if(maxn[to] > maxn[x]) maxn[x] = maxn[to], b[x] = b[to];
}
}
signed main() {
cin >> n >> k; ++k; ans = 2 * (n - 1);
for(int i = 2;i <= n; ++i) G[read()].pb(i);
dep[0] = -1; dfs(1, 0); // dep[1] = 0
for(int i = 2;i <= n; ++i) a[i].id = b[i], a[i].x = maxn[i] - 2 * dep[i] + 2;
sort(a + 1, a + n + 1);
for(int i = 1, cnt = 1;i <= n and cnt <= k; ++i) {
if(a[i].x <= 0) break ;
if(vis[a[i].id]) continue ;
ans -= a[i].x, vis[a[i].id] = 1; ++cnt;
}
cout << ans;
return 0;
}
int read() {
char c; int sum = 0; while(c < '0' or c > '9') c = getchar();
while(c >= '0' and c <= '9') sum = (sum << 3) + (sum << 1) + (c ^ 48), c = getchar();
return sum;
}