【题解】CF2018C Tree Pruning

分析

好像官方题解是反向求解的,这里提供一个正向求解的思路,即直接求出最后所有叶节点到根的距离相同为 \(x\) 时需要删除的结点数 \(ans_x\)

如果我们最后到根的相同距离为 \(x\),那么答案有两个组成部分。

第一个部分,若到根距离为 \(x\) 的结点是一个中间结点,也就是说这个结点还有子节点,那么直接把比这个点更深的子树都删掉即可。

第二个部分,对于每一个分枝,若这个分支的最深深度小于 \(x\) ,那么这一整个分支都得删掉。因为这个分枝只要有剩余,它的叶节点到根的距离一定小于 \(x\) 。只有被完全剪掉,才会不剩余叶节点,才会没有到根距离小于 \(x\) 的叶节点。

因此,我们只需要处理出所有剪完后叶节点到根的距离的删减数,再所有答案取最小就行了,而这个过程,也只需要一次 DFS 就能完成。

对于第一个部分,只需要在 DFS 的过程维护一下下方子树的大小,在每一层加上所有下方子树大小即可。

对于第二个部分,对于每一个点,我们记录一下这个点所代表的子树的最深深度,那么想一下,是不是只要最后要保留的叶节点到根的距离大于这个结点的深度,这个结点就得被删掉。

所以,我们可以用 差分数组 来维护这一件事。
\(mx_i\) 为结点 \(i\) 的子树的最深深度,\(z\) 数组是第二部分的答案数组的差分数组,因此每一个点对第二部分的答案数组贡献就是对 \(z_{mx_i + 1} + 1\)

最后,把两部分的答案加一下就行了,然后对所有情况的答案取最小即可。

上代码!

AC CODE

#include <bits/stdc++.h>
#define int long long
#define inf INT64_MAX
#define ull unsigned long long

using namespace std;

const int N = 6e5 + 9;
int d[N], k[N], sz[N], z[N];
//d:当前结点深度  k:保留的距离要减掉的结点数  sz:当前结点代表的子树大小  z:第二部分答案的差分数组
int mx[N];//当前结点最深深度
int dmx;

vector<int> g[N];

void dfs(int st, int pre)//st:当前结点  pre:父节点
{
	if(st != 1)d[st] = d[pre] + 1;
	dmx = max(dmx, d[st]);//求出整棵树的最深深度
	
	sz[st] = 1;
	
	if(g[st].size() == 1 && st != 1)
	{
		mx[st] = d[st];
	}
	 
	for(auto &i : g[st])
	{
		if(i == pre)continue;
		
		dfs(i, st);
		k[d[st]] += sz[i];//第一部分答案
		sz[st] += sz[i];
		mx[st] = max(mx[st], mx[i]);
	}
	
	if(st != 1)z[mx[st] + 1] ++;//给第二部分答案做贡献
}

void init(int n)
{
	for(int i = 1;i <= n + 10;i ++)
	{
		g[i].clear();
		k[i] = 0;
		sz[i] = 0;
		z[i] = 0;
		mx[i] = 0;
	}
	dmx = 0;
}

void solve()
{
	int n;cin >> n;
	
	init(n);
	
	for(int i = 1;i < n;i ++)
	{
		int u, v;cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	
	d[1] = 0;
	dfs(1, -1);
	
	for(int i = 1;i <= dmx;i ++)z[i] += z[i - 1];//差分数组前缀和求出第二部分的答案
	for(int i = 1;i <= dmx;i ++)k[i] += z[i];//两部分答案求和
	
	int ans = inf;
	
	for(int i = 1;i <= dmx;i ++)ans = min(ans, k[i]);
	
	cout << ans << '\n';
}

signed main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);

    int t = 1;cin >> t;
    while(t --)solve();

    return 0;
}

posted @ 2024-12-10 18:32  天天超方的  阅读(52)  评论(0)    收藏  举报