• [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
  • 相关阅读:
    Greedy Gift Givers 贪婪的送礼者
    USACO 1.1.3 Friday the Thirteenth 黑色星期五
    Prime Matrix(暴力出奇迹)
    博弈论
    好车牌
    C语言中动态内存的分配(malloc,realloc)
    Saruman's Army(贪心)
    Python练习——循环2
    Fox and Number Game
    Repair the Wall (贪心)
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13826183.html
Copyright © 2020-2023  润新知