【UER #4】被删除的黑白树

\(\text{Problem}:\)【UER #4】被删除的黑白树

\(\text{Solution}:\)

等价于白点数量最少。

假设初始所有点都是黑色的,现在要选择一些点使其变为白色,可以贪心考虑:

  • 原树深度最小的叶子结点到根路径上的点全是黑色。
  • 使得深度更小的结点变为白色。

对于第一点,若不满足,则根到所有叶子结点路径上必有白点,而这显然不是最优。具体的,遇到白点就将其变为黑色,然后回溯,子树内叶子结点到根路径上白点个数减一。不难发现这会使得深度最小的叶子结点到根的路径上不存在白点。对于第二点,基于第一点的构造方式分析,必然是更优的。

那么维护子树内叶子结点的最小深度 \(mi_{x}\)。设 \(w\)\(x\) 到根的路径上白点个数,若 \(mi_{x}-w>mi_{1}\),子树内必不满足条件,故修改 \(x\) 为白点。总时间复杂度 \(O(n)\)

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=100010; 
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,d[N],mi[N],ans;
int head[N],maxE; struct Edge { int nxt,to; }e[N<<1];
inline void Add(int u,int v) { e[++maxE].nxt=head[u]; head[u]=maxE; e[maxE].to=v; }
void DFS1(int x,int fa)
{
	d[x]=d[fa]+1, mi[x]=1e9;
	for(ri int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		DFS1(v,x);
		mi[x]=min(mi[x],mi[v]);
	}
	if(mi[x]==1e9) mi[x]=d[x];
}
void DFS2(int x,int fa,int w)
{
	if(mi[x]-w>mi[1]) ans--, w++;
	for(ri int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		DFS2(v,x,w);
	}
}
signed main()
{
	n=read(); ans=n;
	for(ri int i=1;i<n;i++)
	{
		int u,v;
		u=read(), v=read();
		Add(u,v), Add(v,u);
	}
	DFS1(1,0);
	DFS2(1,0,0);
	printf("%d\n",ans);
	return 0;
}
posted @ 2021-05-13 20:56  zkdxl  阅读(88)  评论(1编辑  收藏  举报