[cf1396E]Distance Matching

根据$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 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/13826183.html