Codeforces 911F Tree Destruction(贪心 && 树的直径)
题目链接 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; }