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;
}