[説明] CJOI2019ニワトリ泥棒ツリー(構造タイトル)

[説明] CJOI2019ニワトリ泥棒ツリー(構造タイトル)

鶏泥棒\(N- \)ツリーノード。
鶏泥棒は、このツリーは、各エッジはエッジをカットしているため、任意の泥棒はこの木もしないことができます木のボール側を盗んだ、あまりにも安全ではないと思う
渡します。この木を保護するために、鶏泥棒は木が無重力エッジになるように、いくつかのエッジを追加し、リングの自己ビュー、およびいずれかの側を削除することを決定し
、それはまだユニコム後。
しかし、各エッジを追加すること、料金を持っています。鶏泥棒がプレイステーション4を購入するのに十分なお金を節約したいと思いますので、彼は知りたいと思った、少なくとも追加する
エッジの数を加えたこと?もちろん、単に数を知ることは十分ではありません、いくつかのテストポイントでは、彼はエッジを追加する方法を知りたいと思いました。

答えは明らかに最適下限である\(\ lfloor \ dfrac {C} + 1 2 \ rfloorの\)、\は(C \)リーフノードの数である(ルートの程度を保証しません)。(考えてみましょう:葉ノードの親側を停止します)

このような構成方法を考慮し、リーフノードは、そのに接続されている\(LCA \)別のルートノードであり、残りの1点があっても、ルートに追加されます。それは、各サブツリーのリーフノード内になるよう未満で、ルートノードを見つける\(\ lfloor \ dfrac {C + 1} 2 \ rfloorの\)

直接要求\(DFS \)配列、得られた葉を添加したアレイ(\ \ VE) \は、(\ [I] VE)\(VEの[iが\ lfloor + \ \ dfrac {C + 1} 2 \ rfloor]を接続、ルートノードへの余分な接続の場合。

明らかに\(VEの[i]が\)\(VEの[I + \ lfloor \ dfrac {C + 1} 2 \ rfloor] \) \(LCAが\)ルートです。

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}

const int maxn=5e5+5;
int dr[maxn];
struct E{
      int to,nx;
      E(){to=nx=0;}
      E(const int&a,const int&b){to=a;nx=b;}
}e[maxn<<1];
vector<int> ve;
int head[maxn];
int n,rt,ans,op,cnt;
inline void add(const int&fr,const int&to,const int&b){
      e[++cnt]=E(to,head[fr]);
      head[fr]=cnt;
      ++dr[fr];
      if(dr[fr]>1)rt=fr;
      if(b)add(to,fr,0);
}

void dfs(const int&now,const int&last){
      if(dr[now]==1) ve.push_back(now);
      for(register int t=head[now];t;t=e[t].nx)
        if(e[t].to!=last) dfs(e[t].to,now);
}

int main(){
      //freopen("tree.in","r",stdin);
      //freopen("tree.out","w",stdout);
      n=qr();op=qr();
      for(register int t=1;t<n;++t) add(qr(),qr(),1);
      dfs(rt,0);
      int sz=ve.size();
      printf("%d\n",(sz+1)>>1);
      if(!op)return 0;
      for(register int t=0;t<(sz>>1);++t)
        printf("%d %d\n",ve[t],ve[t+(sz>>1)]);
      if(sz&1) printf("%d %d",ve[sz-1],rt);
      return 0;
}

おすすめ

転載: www.cnblogs.com/winlere/p/11299132.html