题目大意:给出一棵树,进行n-1次操作。每次操作包括找两个点,距离加到ans中,再删除其中一个点,n-1次操作后将只剩1个点,求最大ans。

题解:先求出树的直径,两个端点为p1、p2,操作分2种。

第一种,删除非直径上的点(a、b、c),如图

                            


操作时,选择的点对为{a,max(p1,p2)},max(p1,p2)表示a到p1,p2距离最大的点,删除的点为a。

第二种,删除直径上的点

                            

操作时,从左至右依次操作相邻的两个点即可,删除最左边的点。


代码:

#include<bits/stdc++.h>
#define N 200010
#define INF 1e9
#define LL long long
using namespace std;

int d1[N],d2[N],a[N],b[N],c[N],f[N],du[N];
vector<int>G[N];
queue<int>q;
void dfs(int x,int fa,int *d)
{
    for (int i=0;i<G[x].size();i++)
    {
        int v=G[x][i];
        if (v!=fa)
        {
            d[v]=d[x]+1;
            dfs(v,x,d);
        }
    }
}

void out(int x,int fa,int p2)
{
    for(int i=0;i<G[x].size();i++)
    {
        int v=G[x][i];
        if (!f[v] && v!=fa)
        {
            printf("%d %d %d\n",x,p2,x);
            out(v,x,p2);
        }
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int j,k;
        scanf("%d%d",&j,&k);
        G[j].push_back(k);G[k].push_back(j);du[k]++,du[j]++;
    }
    int p1,p2,m=0;
    d1[1]=0;dfs(1,-1,d1);
    for (int i=1;i<=n;i++) if (m<d1[i]) { m=d1[i];p1=i;}
    d1[p1]=0;dfs(p1,-1,d1); m=0;
    for (int i=1;i<=n;i++) if (m<d1[i]) { m=d1[i];p2=i;}
    d2[p2]=0;dfs(p2,-1,d2);
    LL ans=0;m=0;
    for (int i=1;i<=n;i++) if(d1[i]+d2[i]!=d1[p2] && du[i]==1) q.push(i);
    while(!q.empty())
    {
        int i=q.front();q.pop();
        for (int u=0;u<G[i].size();u++)
        {
            int v=G[i][u];if (f[v])continue;
            ans+=max(d1[i],d2[i]);
            a[++m]=i;b[m]=d1[i]>d2[i]?p1:p2;c[m]=i;f[i]=1;
            du[v]--;
            if(du[v]==1) q.push(v);
        }
    }
    ans+=(LL) (1+d1[p2])*d1[p2]/2;
    printf("%I64d\n",ans);
    for (int i=1;i<=m;i++) printf("%d %d %d\n",a[i],b[i],c[i]);
    out(p1,-1,p2);
}