1. 程式人生 > >Codeforces 911F Tree Destruction(貪心 && 樹的直徑)

Codeforces 911F Tree Destruction(貪心 && 樹的直徑)

span aps con lan dfs delta scanf auto ems

題目鏈接 Tree Destructi

題意 給定一棵樹,每次可以選定樹上的兩個葉子,並刪去其中的一個。答案每次加上兩個選定的葉子之間的距離。

  求最後答案的最大值。

首先求出樹的某一條直徑,令其端點分別為L, R。

把L看成樹的根,那麽R一定是葉子結點。

對於那些非直徑上的點,離他們最遠的點肯定是L或R中的一個(可能也有其他的,但是L或R肯定已經最大了)

所以依次把這些非直徑上的點刪掉,刪掉的時候在L和R中選擇一個就行了。

最後把直徑刪掉即可。

時間復雜度$O(nlogn)$ (應該是可以做到$O(n)$的,但是我比較懶)

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

typedef long long LL;

const int N = 2e5 + 10;

vector <int> v[N];

int n;
int cnt;
int x, y;
int L, R;

int f[N][20];
int a[N];
int deep[N], father[N];
int Father[N];
int vis[N];
int c[N];
int isroot[N];

LL ans = 0;

queue <int> q;

void dfs(int x, int fa, int now){
	deep[x] = now;
	if (fa){
		f[x][0] = fa;
		for (int i = 0; f[f[x][i]][i]; ++i)
			f[x][i + 1] = f[f[x][i]][i];
	}

	if (now > cnt) cnt = now, L = x;
	for (auto u : v[x]){
		if (u == fa) continue;
		dfs(u, x, now + 1);
	}
}

void dfs2(int x, int fa, int now){
	father[x] = fa;
	if (now > cnt) cnt = now, R = x;
	for (auto u : v[x]){
		if (u == fa) continue;
		dfs2(u, x, now + 1);
	}
}

int LCA(int a, int b){
	if (deep[a] < deep[b]) swap(a, b);
	for (int i = 0,  delta = deep[a] - deep[b]; delta; delta >>= 1, ++i)
		if (delta & 1) a = f[a][i];

	if (a == b) return a;
	dec(i, 19, 0) if (f[a][i] != f[b][i]){
		a = f[a][i];
		b = f[b][i];
	}

	return f[a][0];
}

int dis(int x, int y){
	int z = LCA(x, y);
	return deep[x] + deep[y] - 2 * deep[z];
}

void dfs3(int x, int fa){
	vis[x] = 1;
	Father[x] = fa;
	for (auto u : v[x]){
		if (vis[u]) continue;
		dfs3(u, x);
		++c[x];
	}
}


int main(){

	scanf("%d", &n);
	rep(i, 1, n){
		scanf("%d%d", &x, &y);
		v[x].push_back(y);
		v[y].push_back(x);
	}

	L = 0, cnt = 0;
	dfs(1, 0, 0);

	cnt = 0;
	R = 0;
	memset(father, 0, sizeof father);
	dfs2(L, 0, 0);

	cnt = 0;
	x = R;
	while (x){
		++cnt;
		a[cnt] = x;
		x = father[x];
	}

	memset(vis, 0, sizeof vis);
	rep(i, 1, cnt) vis[a[i]] = 1;
	rep(i, 1, n)  isroot[i] = vis[i];
	rep(i, 1, n) if (!vis[i]){
		int now = max(dis(i, L), dis(i, R));
		ans += 1ll * now;
	}


	memset(c, 0, sizeof c);
	rep(i, 1, cnt) dfs3(a[i], 0);
	rep(i, 1, n) if (c[i] == 0 && !isroot[i]) q.push(i);

	ans = ans + 1ll * cnt * (cnt - 1) / 2;
	printf("%lld\n", ans);


	while (!q.empty()){
		x = q.front(); q.pop();
		vis[x] = 1;
		int al = dis(x, L), ar = dis(x, R);
		if (al > ar) printf("%d %d %d\n", L, x, x);
		else printf("%d %d %d\n", R, x, x);

		int u = Father[x];
		--c[u];
		if (c[u] == 0 && !isroot[u]) q.push(u);
	}

	rep(i, 1, cnt - 1) printf("%d %d %d\n", a[i], a[cnt], a[i]);
	return 0;
}

Codeforces 911F Tree Destruction(貪心 && 樹的直徑)