C Cover the Tree 2020牛客多校训练营第二场

https://ac.nowcoder.com/acm/contest/5667/C

叶子节点的个数tot,答案肯定是tot/2+(tot&1),叶子节点两两配对就行

首先树形dp找到一个根节点rt,子树v中中包含的叶子节点为son[v],他的所有子树中son[v]最大的最小,设这个根节点为rt

然后把每个子树v中的叶子节点放到队列q[v]中,然后每次取剩余叶子节点最多的两个子树作为路径,用set动态维护队列大小

最后如果剩多了一个就直接到这个根节点rt。这样的每次取最大的两个很显然是对的,因为子树中最大son[v]的一定满足son[v]<=tot/2,因为如果son[v]>tot/2,就可以把根节点这个最大子树移动,让他的父节点的所有叶子节点tot-son[v]<=tot/2变成一棵子树,然后把son[v]这个大于一半的拆解掉

题解好像有O(n)构造方法,还要学习一个

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=3e5+10;

int n,m,cas,k,cnt,tot,ans,rt;
int dp[maxl],du[maxl],son[maxl],fa[maxl];
bool in[maxl],vis[maxl]; 
vector<int> e[maxl];
queue<int> q[maxl];
typedef pair<int,int> p;
set<p> s;
set<p> ::iterator itl,itr;

inline void dfs1(int u)
{
	vis[u]=true;bool flag=false;
	for(int v:e[u])
	if(!vis[v])
	{
		flag=true;
		fa[v]=u;dfs1(v);
		son[u]+=son[v];
	}
	if(!flag)
		son[u]=1;
}

inline void dfs2(int u,int f)
{
	int mx=f;
	for(int v:e[u])
	if(fa[v]==u)
		mx=max(mx,son[v]);
	dp[u]=mx;
	for(int v:e[u])
	if(fa[v]==u)
		dfs2(v,tot-son[v]);
}

inline void prework()
{
	scanf("%d",&n);
	int u,v;
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d%d",&u,&v);
		e[u].push_back(v);du[u]++;
		e[v].push_back(u);du[v]++;
	}
	tot=0;
	for(int i=1;i<=n;i++)
	if(du[i]==1) 
		tot++;
	dfs1(1);
	dfs2(1,0);
} 

inline void dfs3(int u,int id)
{
	vis[u]=true;bool flag=false;
	for(int v:e[u])
	if(!vis[v])
	{
		flag=true;
		dfs3(v,id);
	}
	if(!flag)
		q[id].push(u);
}

inline void mainwork()
{
	for(int i=1;i<=n;i++) vis[i]=false;
	dp[0]=tot;rt=0;
	for(int i=1;i<=n;i++)
	if(dp[i]<dp[rt])
		rt=i;
	cnt=0;vis[rt]=true;
	for(int v:e[rt])
		dfs3(v,++cnt);
	for(int i=1;i<=cnt;i++)
		s.insert({q[i].size(),i});
}

inline void print()
{
	if(n==1)
	{
		puts("0");
		return;
	}
	if(n==2)
	{
		puts("1");
		puts("1 2");
		return;
	}
	ans=tot/2+(tot&1);
	printf("%d\n",ans);
	int idl,idr;p l,r;
	for(int i=1;i<=ans;i++)
	{
		itr=s.end();--itr;r=(*itr);
		s.erase(itr);
		itl=s.end();--itl;l=(*itl);
		s.erase(itl);
		if(l.first==0)
		{
			idr=r.second;
			printf("%d %d\n",q[idr].front(),rt);
			return;
		}
		idl=l.second;idr=r.second;
		printf("%d %d\n",q[idl].front(),q[idr].front());
		q[idl].pop();q[idr].pop();
		
		s.insert({q[idl].size(),idl});
		s.insert({q[idr].size(),idr});
	}
}

int main()
{
	int t=1;
	//scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/107322833