Editorial for Tree Royale
Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.
Submitting an official solution before solving the problem yourself is a bannable offence.
Author:
Let the tree whose root is not connected to any other tree be denoted by .
It is clear that such a tree will always exist.
Step 1 - Using All Trees in the Diameter
It is evident that the optimal answer will always include all trees that lie along the diameter of the combined structure.
Reason: Suppose a tree is not part of the diameter. Then we could detach that tree from its current position and connect its root to one of the endpoints of the current diameter, thereby increasing the overall diameter - a contradiction.
Also note that this particular tree cannot be part of the diameter.
Step 2 - Contribution of Each Tree
For each tree:
- If it is not
, it contributes to the diameter with the longest path from its root to one of its leaves.
- If it is
, it contributes with its full diameter.
Why?
- For non-
trees, the connecting point is the root, so only the longest root-to-leaf path is relevant.
- For
, since it is an independent tree, its full diameter can appear in the final diameter path.
Step 3 - Definitions
Let:
= diameter of tree
.
= longest path length from the root of
to any of its leaves.
Step 4 - Computing the Final Diameter
Let the final diameter length be .
It can be shown that:
where:
- Index
is the choice of the special tree
. We add
to account for the edges introduced when joining the
individual trees into a single connected structure. Each connection between two trees adds exactly one edge, and connecting
trees requires
such edges. Once all
and
are computed, this expression can be evaluated efficiently.
C++ Solution:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define all(c) (c).begin(), (c).end()
#define rall(c) (c).rbegin(), (c).rend()
#define fr first
#define sc second
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;
const int MAXN = 1e6 + 16, MAXM = 1e2 + 10;
int n;
vector <int> adj[MAXN];
int mxh[MAXN], d;
void DFS(int v) {
int mx1 = 0, mx2 = 0;
for (auto u: adj[v]) {
DFS(u);
mxh[v] = max(mxh[v], mxh[u] + 1);
if (mxh[u] + 1 > mx1) mx2 = mx1, mx1 = mxh[u] + 1;
else if (mxh[u] + 1 > mx2) mx2 = mxh[u] + 1;
}
d = max(d, mx1 + mx2);
}
int main() {
ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
int tt;
cin >> tt;
while (tt--) {
int m;
cin >> m;
int sm = 0, mx = 0;
for (int t = 0; t < m; t++) {
cin >> n;
for (int i = 0; i < n; i++) adj[i].clear();
for (int i = 0; i < n; i++) mxh[i] = 0;
d = 0;
for (int i = 1, p; i < n; i++) {
cin >> p;
adj[--p].pb(i);
}
DFS(0);
sm += mxh[0];
mx = max(mx, d - mxh[0]);
}
cout << sm + mx + m - 1 << endl;
}
return 0;
}
Python solution:
import sys, io
input = sys.stdin.readline
adj = []
max_heights = []
diameter = 0
def dfs(v):
global adj, max_heights, diameter
# Diameter is the sum of the highest two depths, we can store both
mh = mh2 = 0
for u in adj[v]:
dfs(u)
max_heights[v] = max(max_heights[v], max_heights[u]+1) # 1+childs height
# Maintain highest and second highest height
if (max_heights[u]+1 > mh):
mh2 = mh
mh = max_heights[u]+1
elif (max_heights[u]+1 > mh2):
mh2 = max_heights[u]+1
# Maintain max diameter as sum of the two highest heights in the tree
diameter = max(diameter, mh+mh2)
t = int(input())
# For each test case
for _ in range(t):
n = int(input()) # Number of trees
total_heights = 0 # All trees besides one will contribute their max height
max_diameter = 0 # A single tree will contribute its diameter as root, we store the max one
for _ in range(n):
m = int(input()) # Vertices of current tree
adj = [[] for _ in range(m)]
max_heights = [0 for _ in range(m)]
diameter = 0
parents = [int(x) for x in input().split()]
for i in range(1, m):
adj[parents[i-1]-1].append(i)
dfs(0)
total_heights += max_heights[0]
# The tree that contributes its diameter doesn't contribute its height,
# so we offset that here
max_diameter = max(max_diameter, diameter-max_heights[0])
# n-1 new edges are formed from merging the trees
print(max_diameter + total_heights + n - 1)
Comments