题目链接:点击打开链接
题意:给一棵树(n个顶点,n-1条边),初始化一个值为0,每次选择树中两个顶点并删去其中一个,并加这两点的路径长加到该值上,直到删完所有边,求该值达到最大时的操作顺序和该值大小。
思路:找出树的直径,并对直径外的点从外到内依次删除(这里我粗暴的用了排序,路径长大的先输出,可优化),最后从直径的一个端点依次删除直径上的其他点,这样就能达到最大值。
AC代码如下:(950鶸T)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
int n;
vector<vector<int>> tree;
int record[200005];
int flag[200005];
int relen[3][200005];
int be, en, mid;
long long maxw;
struct an{
int a, b;
int dis;
an(int a, int b, int c):a(a),b(b),dis(c) {}
};
bool operator <(an& a, an& b)
{
return a.dis>b.dis;
}
vector<an> anset;
int flw(int v)
{
memset(flag,0,sizeof(int)*n+1);
flag[v] = 1;
long long tempw = 0;
queue<int> re; re.push(v);
while(1)
{
int s = re.size();
int tt = re.front();
for(int i=0;i<s;++i)
{
tt = re.front();
for(int i=0;i<tree[tt].size();++i)
if(flag[tree[tt][i]] == 0)
{
flag[tree[tt][i]] = 1;
re.push(tree[tt][i]);
}
re.pop();
}
if(re.empty()) {maxw = max(maxw,tempw); return tt;}
else tempw++;
}
}
void fds(int root, int num)
{
queue<int> re;
re.push(root);
memset(flag,0,sizeof(flag));
flag[root] = 1;
re.push(root);
while(!re.empty())
{
int s = re.size();
for(int i=0;i<s;++i)
{
int tt = re.front();
for(int i=0;i<tree[tt].size();++i)
{
if(!flag[tree[tt][i]])
{
relen[num][tree[tt][i]] = relen[num][tt] + 1;
flag[tree[tt][i]] = 1;
re.push(tree[tt][i]);
}
}
re.pop();
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
for(int i=0;i<200000;++i)
{
vector<int> temp;
tree.push_back(temp);
}
while(cin>>n)
{
maxw = -1;
for(int i=0;i<n;++i)
tree[i].clear();
for(int i=0;i<n-1;++i)
{
int a, b;
cin>>a>>b;
tree[a].push_back(b);
tree[b].push_back(a);
}
be = flw(1);
en = flw(be);
long long ans = maxw*(maxw+1)/2;
relen[1][be] = relen[2][en] = 0;
fds(be,1);
fds(en,2);
anset.clear();
for(int i=1;i<=n;++i)
{
int a = relen[1][i];
int b = relen[2][i];
if(a+b != maxw)
{
if(a>b) {ans+=a; anset.push_back(an(be,i,a)); }
else {ans+=b; anset.push_back(an(en,i,b)); }
}
else record[a] = i;
}
sort(anset.begin(),anset.end());
cout<<ans<<endl;
for(int i=0;i<anset.size();++i)
{
cout<<anset[i].a<<" "<<anset[i].b<<" "<<anset[i].b<<endl;
}
for(int i=maxw;i>=1;--i)
{
cout<<be<<" "<<record[i]<<" "<<record[i]<<endl;
}
}
return 0;
}