【题解】[Codeforces Gym 101234 I] Tree Game | 20210930 模拟赛 树(tree)【贪心】

题目链接

题目链接

题意

给个一棵树,初始所有边都是白色;每次操作选择两个叶子,要求它们之间所有边为白色,将这些边染黑,直到无法操作为止。问至少需要多少次操作。\(n\leq 5\times 10^5\)

题解

考虑对于一个子树内贪心。一个子树内最多可能有两个叶子留到父亲,考虑一个点分别有多少儿子留下了一个/两个叶子,将留了两个的两两配对,留了一个的同理,留了两个的如果有剩则与留了一个的配对。

#include<bits/stdc++.h> 
using namespace std;
int getint(){ int x;scanf("%d",&x);return x; }
const int N=5e5+10;
vector<int>to[N];
int ans=0;

int ss(int x,int fa){
	if(to[x].size()==1)return 1;
	int c[3]={0,0,0};
	for(int v:to[x]){
		if(v==fa)continue;
		c[ss(v,x)]++;
	}
	while(c[1]>2)c[1]-=2,++ans;
	while(c[2]>1)c[2]-=2,++ans;
	if(c[1]>=2&&c[2]>=1)c[1]=1,c[2]-=1,++ans;
//	cerr<<"> "<<x<<" "<<c[1]<<" "<<c[2]<<endl;
	return min(2,c[1]+c[2]*2);
}
int main(){
//	freopen("A2.in","r",stdin);
//	freopen("A1.out","w",stdout);
	int n=getint();
	if(n==1)return puts("0"),0;
	if(n==2)return puts("1"),0;
	for(int i=0;i<n-1;i++){
		int x=getint(),y=getint();
		to[x].push_back(y);
		to[y].push_back(x);
	}
	int rt=1;
	while(to[rt].size()==1)++rt;
	ans+=ss(rt,0)/2;
	cout<<ans<<endl;
}

花絮:本题的搬题人的数据包中有几个数据点输出为空

posted @ 2021-09-30 19:45  破壁人五号  阅读(68)  评论(0编辑  收藏  举报