Educational Codeforces Round 35 (Rated for Div. 2) F. Tree Destruction

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);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值