根据$dis(x,y)=d[x]+d[y]-2d[lca(x,y)]$,由于所有点都出现了1次,距离即$sum_{i=1}^{n}d_{i}-2sum d[lca(x,y)]$(以下假设根深度为0)
构造:以重心$r$为根,选择$r$的所有儿子中子树大小最大的两个,从这两颗子树中各选一个点匹配并删除,利用重心性质可以使得所有$d[lca(x,y)]=0$,即得到答案最大值$sum_{i=1}^{n}d_{i}$(距离与根无关)
答案要求为$k$,令$k'=frac{sum_{i=1}^{n}d_{i}-k}{2}$(若无法整除2则显然无解),我们要让所有$d[lca(x,y)]$之和为$k'$
构造:选择$r$的所有儿子中最大的1个,若$k'ge d-1$($d$为该子树深度),则从中选出2个点使得lca深度为$d-1$(选择最深的点和其兄弟,若没有兄弟改为和其父亲),之后$k'-=d-1$,否则找到深度为$k'$且不为叶子的点(必然存在,因为整颗树深度为$d$),将其与其儿子匹配即可
具体实现中,对每颗子树需要支持:1.删除一个点;2.查询某深度的点,用set维护,同时外部还需要用优先队列来维护子树大小,时间复杂度都是$o(nlog_{2}n)$,常数可能稍大
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 struct ji{ 5 int nex,to; 6 }edge[N<<1]; 7 set<pair<int,int> >s[N]; 8 set<pair<int,int> >::iterator it; 9 priority_queue<pair<int,int> >q; 10 pair<int,int>ans[N]; 11 int E,n,r,x,y,z,cnt,head[N],sz[N],mx[N],f[N],d[N]; 12 long long m; 13 void add(int x,int y){ 14 edge[E].nex=head[x]; 15 edge[E].to=y; 16 head[x]=E++; 17 } 18 void dfs(int k,int fa){ 19 sz[k]=1; 20 mx[k]=0; 21 for(int i=head[k];i!=-1;i=edge[i].nex) 22 if (edge[i].to!=fa){ 23 dfs(edge[i].to,k); 24 sz[k]+=sz[edge[i].to]; 25 mx[k]=max(mx[k],sz[edge[i].to]); 26 } 27 if (max(n-sz[k],mx[k])<=n/2)r=k; 28 } 29 void dfs(int k,int fa,int sh){ 30 f[k]=fa; 31 d[k]=sh; 32 m-=sh; 33 s[x].insert(make_pair(sh,k)); 34 sz[k]=1; 35 for(int i=head[k];i!=-1;i=edge[i].nex) 36 if (edge[i].to!=fa){ 37 dfs(edge[i].to,k,sh+1); 38 sz[k]+=sz[edge[i].to]; 39 } 40 } 41 int main(){ 42 scanf("%d%lld",&n,&m); 43 memset(head,-1,sizeof(head)); 44 for(int i=1;i<n;i++){ 45 scanf("%d%d",&x,&y); 46 add(x,y); 47 add(y,x); 48 } 49 dfs(1,0); 50 for(int i=head[r];i!=-1;i=edge[i].nex){ 51 x=edge[i].to; 52 dfs(x,r,1); 53 q.push(make_pair(sz[x],x)); 54 } 55 if ((m>0)||(m%2)){ 56 printf("NO"); 57 return 0; 58 } 59 m/=-2; 60 while (m){ 61 x=q.top().second; 62 q.pop(); 63 if (sz[x]<2){ 64 printf("NO"); 65 return 0; 66 } 67 sz[x]-=2; 68 if (sz[x])q.push(make_pair(sz[x],x)); 69 if ((*--s[x].end()).first-1<=m){ 70 y=(*--s[x].end()).second; 71 s[x].erase(--s[x].end()); 72 m-=d[y]-1; 73 z=f[y]; 74 bool flag=0; 75 for(int i=head[z];i!=-1;i=edge[i].nex) 76 if ((edge[i].to!=f[z])&&(edge[i].to!=y)&&(s[x].find(make_pair(d[edge[i].to],edge[i].to))!=s[x].end())){ 77 ans[++cnt]=make_pair(edge[i].to,y); 78 s[x].erase(make_pair(d[edge[i].to],edge[i].to)); 79 flag=1; 80 break; 81 } 82 if (!flag){ 83 ans[++cnt]=make_pair(z,y); 84 s[x].erase(make_pair(d[z],z)); 85 } 86 } 87 else{ 88 it=lower_bound(s[x].begin(),s[x].end(),make_pair((int)m,0)); 89 while ((*it).first==m){ 90 bool flag=0; 91 y=(*it).second; 92 for(int i=head[y];i!=-1;i=edge[i].nex) 93 if ((edge[i].to!=f[y])&&(s[x].find(make_pair(d[edge[i].to],edge[i].to))!=s[x].end())){ 94 ans[++cnt]=make_pair(y,edge[i].to); 95 s[x].erase(make_pair(d[y],y)); 96 s[x].erase(make_pair(d[edge[i].to],edge[i].to)); 97 flag=1; 98 break; 99 } 100 if (flag)break; 101 it++; 102 } 103 m=0; 104 } 105 } 106 while (!q.empty()){ 107 x=q.top().second; 108 q.pop(); 109 if (q.empty()){ 110 ans[++cnt]=make_pair((*s[x].begin()).second,r); 111 break; 112 } 113 y=q.top().second; 114 q.pop(); 115 if (sz[x]>1)q.push(make_pair(--sz[x],x)); 116 if (sz[y]>1)q.push(make_pair(--sz[y],y)); 117 ans[++cnt]=make_pair((*s[x].begin()).second,(*s[y].begin()).second); 118 s[x].erase(s[x].begin()); 119 s[y].erase(s[y].begin()); 120 } 121 printf("YES "); 122 for(int i=1;i<=cnt;i++)printf("%d %d ",ans[i].first,ans[i].second); 123 }