[CF911F]ツリー破壊

問題の説明

あなたがで重み付けされていない木を与えられているn個の頂点。その後、N  - 1以下の操作は、ツリーに適用されます。単一の操作手順は次のとおりです。

  1. 2葉を選びます。
  2. その答えにそれらの間の単純なパスの長さを追加します。
  3. 木から選ばれた葉の1つを削除します。

(操作を適用する前に)最初の答えは後に明らかに0であるN  木は、単一の頂点で構成されます1このような動作- 。

あなたが達成できる最大の可能な答えを計算し、あなたがこの答えを達成することを可能にする一連の操作を構築!

入力形式

最初の行は1つの整数番号含有N(2≤  nは  ツリーの頂点の数- ≤2・105)。

のn  - 1行フォームのツリーのエッジが記述aiは、  BI(1≤  AIBI  ≤の  nは  ≠  BI)。与えられたグラフが木であることが保証されています。

出力フォーマット

最大の可能な答えは - 最初の行では1つの整数番号を印刷します。

次にN  - 1行がそれらの形式で適用のために動作を印刷AI、  BI、  CIAI、  BI、現在の動作(1≤で選択された葉の一対-  AIBI  ≤の  N)、CI(1個の≤  のCI  ≤の  NCI  =  またはCI  =  BI) -現在の操作のツリーから削除され選びだし葉。

より良い理解のための例を参照してください。

サンプル入力

3
1 2
1 3

サンプル出力

3
2 3 3
2 1 1

解決

最も遠いノードから、無権利ツリーの任意のノードに、それは、エンドポイントの直径である必要があります。まず第一に、私たちは自然を知っておく必要があります。そう、貪欲な思考は、毎回リーフノードは、答えを計算し、現在のリーフノードを削除するには、その最遠点から2つのエンドポイントの直径です。左の直径は、それがあるときのポイントは、最後に残ったポイントを削除するには知っています。

コード

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#define int long long
#define N 200002
using namespace std;
queue<int> q;
int head[N],ver[N*2],nxt[N*2],l;
int n,i,dis1[N],dis2[N],a,b,maxx,son[N],fa[N],ans[N][3],cnt;
int read()
{
    char c=getchar();
    int w=0;
    while(c<'0'||c>'9') c=getchar();
    while(c<='9'&&c>='0'){
        w=w*10+c-'0';
        c=getchar();
    }
    return w;
}
void insert(int x,int y)
{
    l++;
    ver[l]=y;
    nxt[l]=head[x];
    head[x]=l;
    son[x]++;
}
void dfs(int x,int pre,int d)
{
    if(d>maxx) maxx=d,a=x;
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y!=pre) dfs(y,x,d+1);
    }
    if(son[x]==1) q.push(x);
}
void dfs1(int x,int pre)
{
    if(dis1[x]>maxx) maxx=dis1[x],b=x;
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y!=pre){
            fa[y]=x;
            dis1[y]=dis1[x]+1;
            dfs1(y,x);
        }
    }
}
void dfs2(int x,int pre)
{
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y!=pre){
            dis2[y]=dis2[x]+1;
            dfs2(y,x);
        }
    }
}
signed main()
{
    n=read();
    for(i=1;i<n;i++){
        int u=read(),v=read();
        insert(u,v);
        insert(v,u);
    }
    dfs(1,0,0);
    maxx=0;
    dfs1(a,0);
    dfs2(b,0);
    int sum=0,d=dis1[b];
    while(!q.empty()){
        while(q.front()==a||q.front()==b) q.pop();
        if(q.empty()) break;
        int x=q.front();
        q.pop();
        sum+=max(dis1[x],dis2[x]);
        son[x]--;
        for(i=head[x];i;i=nxt[i]){
            son[ver[i]]--;
            if(son[ver[i]]==1) q.push(ver[i]);
        }
        cnt++;
        ans[cnt][0]=ans[cnt][2]=x;
        if(dis1[x]>dis2[x]) ans[cnt][1]=a;
        else ans[cnt][1]=b;
    }
    while(b!=a){
        cnt++;
        ans[cnt][0]=a;ans[cnt][1]=b;ans[cnt][2]=b;
        b=fa[b];
        sum+=d;
        d--;
    }
    printf("%lld\n",sum);
    for(i=1;i<=cnt;i++) printf("%lld %lld %lld\n",ans[i][0],ans[i][1],ans[i][2]);
    return 0;
}

概要

ここで思い出に残る良い文字です。

おすすめ

転載: www.cnblogs.com/LSlzf/p/11684891.html