F. Tree Destruction
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given an unweighted tree with n vertices. Then n - 1 following operations are applied to the tree. A single operation consists of the following steps:
choose two leaves;
add the length of the simple path between them to the answer;
remove one of the chosen leaves from the tree.
Initial answer (before applying operations) is 0. Obviously after n - 1 such operations the tree will consist of a single vertex.
Calculate the maximal possible answer you can achieve, and construct a sequence of operations that allows you to achieve this answer!
Input
The first line contains one integer number n (2 ≤ n ≤ 2·105) — the number of vertices in the tree.
Next n - 1 lines describe the edges of the tree in form ai, bi (1 ≤ ai, bi ≤ n, ai ≠ bi). It is guaranteed that given graph is a tree.
Output
In the first line print one integer number — maximal possible answer.
In the next n - 1 lines print the operations in order of their applying in format ai, bi, ci, where ai, bi — pair of the leaves that are chosen in the current operation (1 ≤ ai, bi ≤ n), ci (1 ≤ ci ≤ n, ci = ai or ci = bi) — choosen leaf that is removed from the tree in the current operation.
See the examples for better understanding.
Examples
inputCopy
3
1 2
1 3
output
3
2 3 3
2 1 1
inputCopy
5
1 2
1 3
2 4
2 5
output
9
3 5 5
4 3 3
4 1 1
4 2 2
题意:给一棵树,每次可以选一对叶节点,然后加上这对节点的距离,然后任意删一个。
重复这个过程直至剩一个点,求最大的距离和。
一下子就想到贪心嘛。就是让一对叶节点的距离尽量大,然后把其中一个深度小的点删了。
也就是不断去让一个叶节点去和深度很大的叶节点去做操作,做完了把这个深度小的叶节点删了,让深度大的叶节点被重复利用。
但是我不知道该用什么数据结构去维护这个深度很大的叶节点。
无奈之下搜题解,看到了树的直径这个概念。(不知道的自行百度哈)
然后找到直径的两个端点v1,v2,然后让其他所有的叶节点去和v1或者v2(具体看到v1还是v2更远做选择)做一个操作
然后把所有的非v1,v2叶节点处理完了(可以用出度来判断某个非叶节点是否变成了叶节点),开始安排这条直径。
安排直径很简单,随便你怎么让这根直径的叶节点删,都是对的。
代码还是很长的,先dfs求v1,v2,然后再dfs求v1和v2到其他任何点的距离。
然后最后再dfs求v1到v2这条直径经过的所有点(为了输出)
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N (int)2e5+10
struct node{
int a, b, c;
node(int q, int w, int e){a = q, b = w, c = e;}
};
int c[N], dis1[N], dis2[N], v1, v2, m;
vector<node> arr;
vector<int> e[N];
bool visit[N];
void dfs(int start, int len, int& v)
{
visit[start] = true;
if (len >= m)
{
m = len;
v = start;
}
int i;
for (i = 0; i < e[start].size(); i++)
{
if (!visit[e[start][i]]) dfs(e[start][i], len+1, v);
}
}
void dfs1(int start, int len, int* dis)
{
visit[start] = true;
dis[start] = len;
int i;
for (i = 0; i < e[start].size(); i++)
{
if (!visit[e[start][i]]) dfs1(e[start][i], len+1, dis);
}
}
ll res;
void print(int a, int b, int* dis)
{
arr.push_back(node(a, b, a));
res += dis[a];
}
int s[N], top = -1;
bool flag;
void Find(int now)
{
visit[now] = true;
if (!flag) s[++top] = now;
if (now == v2) flag = true;
int i;
for (i = 0; i < e[now].size(); i++)
{
if (!visit[e[now][i]])
{
Find(e[now][i]);
if (!flag) top--;
}
}
}
int main(void)
{
int n;
scanf("%d", &n);
int i, j;
for (i = 0; i < n - 1; i++)
{
int a, b;
scanf("%d%d", &a, &b);
e[a].push_back(b);
e[b].push_back(a);
c[a]++, c[b]++;
}
memset(visit, false, sizeof(visit)); m = 0; dfs(1, 0, v1);
memset(visit, false, sizeof(visit)); m = 0; dfs(v1, 0, v2);
memset(visit, false, sizeof(visit)); dfs1(v1, 0, dis1);
memset(visit, false, sizeof(visit)); dfs1(v2, 0, dis2);
queue<int> sup;
for (i = 1; i <= n; i++)
{
if (c[i] == 1 && i != v1 && i != v2) sup.push(i);
}
while (!sup.empty())
{
int front = sup.front();
sup.pop(); c[front]--;
if (dis1[front] < dis2[front]) print(front, v2, dis2);
else print(front, v1, dis1);
for (i = 0; i < e[front].size(); i++)
{
if (--c[e[front][i]] == 1) sup.push(e[front][i]);
}
}
memset(visit, false, sizeof(visit)); Find(v1);
for (; top > 0; top--)
{
print(s[top], v1, dis1);
}
printf("%lld\n", res);
for (i = 0; i < n - 1; i++)
{
printf("%d %d %d\n", arr[i].a, arr[i].b, arr[i].c);
}
}