Hello everyone,
finding the diameter is one of the most frequent ways to solve problems about trees. In this tutorial we will see how to find a diameter and some of its properties, and we will use them to solve some problems of increasing difficulty.
The first part of the tutorial is quite basic, so feel free to skip it and jump to the problems if you already know the concepts.
Target: rating [1400,2100] on CF
Prerequisites: basic graph theory, greedy
The diameter
Given an unweighted tree, let's define dist(a,b)= the number of edges in the simple path a→b.
A diameter of the tree is a simple path a→b that maximizes dist(a,b) over all pairs of nodes. If there are multiple diameters, let's pick any of them.
The same definition is valid for a weighted tree with nonnegative weights (with dist(a,b)= the sum of the weights of the edges in the simple path a→b).
Finding a diameter
Given a tree with n nodes are multiple ways to find a diameter. Here is one of the simplest ways:
Run a DFS from any node p. Let a be a node whose distance from node p is maximized. Run another DFS from node a. Let b be a node whose distance from node a is maximized. a→b is a diameter.
Tree = edges of a diameter + forest
Before proving the previous algorithm, let's analyze the structure of the tree (we will mention the diameter, but we will not use the fact that a→b is actually a diameter before proving it).

We started a DFS from node p=16, and we got that node a=1 is the farthest from p, and node b=7 is the farthest from a.
Let's represent the diameter on a line. If you remove the edges of the diameter, you get a forest (i.e., several trees). Let's root each tree at the node in the diameter. What's the height (i.e., the maximum distance from the root to any node) of each component?
Let q be the root of the component of p. Let's consider any component whose root d is between a (included) and q (excluded), and one of its nodes c.
We get
dist(p,a)≥dist(p,c)⟹dist(p,a)−dist(p,d)≥dist(p,c)−dist(p,d)⟹dist(a,d)≥dist(c,d).
In other words, the height of each component with root in the left half of the diameter (i.e., dist(a,d)<dist(d,b)) is at most the distance of the root of the component from the left end of the diameter.
You can prove the same statement for the right half of the diameter (i.e., dist(a,d)≥dist(d,b)), using that b is the farthest node from a.
Farthest node for each node
For each node i, let's find a node j such that dist(i,j) is maximum.
Claim: j=a or j=b always works.
Proof:

- If j=j1 works (j1 is not in the same component of i; let's assume without loss of generality that j1 is closer to a than to b), dist(i,j1)=dist(i,r)+dist(r,j1)≤dist(i,r)+dist(r,a)=dist(i,a). Then, j=a also works.
- If j=j2 works (j2 is in the same component of i), dist(i,j1)≤dist(i,r)+dist(r,j1)≤dist(i,r)+dist(r,a)=dist(i,a). Then, j=a also works.
Proof that a→b is a diameter
Now we can finish the proof.
Suppose that u→v is a diameter. We have either dist(u,a)≥dist(u,v) or dist(u,b)≥dist(u,v) (see "Farthest node for each node").
Let's assume without loss of generality that dist(u,b)≥dist(u,v). We get dist(a,b)≥dist(u,b)≥dist(u,v), so a→b is a diameter.
Observations
The algorithm also works in a weighted tree with positive edges (we've never used that the weights are 1).
However, it doesn't work on general graphs (discussion).
How to use the diameter

Most of the times, spamming "the farthest node from each node is one end of the diameter" and "the height of each component is smaller than the distance to the closest end of the diameter" is enough to reduce the problem to something simpler.
You may need to consider any path of the tree. Find a diameter a→b. There are two cases: the path intersects (blue) or doesn't intersect (green) the diameter.
Then, you may wonder how to make the path longer / "more optimal" / etc. according to the statement. For example, you may need to use dist(7,5)≥dist(5,19) to show that 8→7 is "more optimal" than 8→19.
Hint 1First, put the shops on any path of (unweighted) length k. Can you choose a better path?
Hint 2The optimal path lies completely on the (weighted) diameter.
Hint 3Try all possible paths in O(n).
SolutionThe optimal path lies completely on the (weighted) diameter. Sketch of proof: suppose that the intersection of the chosen path with the diameter is a path u→v (a,u,v,b in this order). Then, the maximum distance between a node and the nearest shop is one of the following: dist(a,u), dist(v,b), dist(c,d) (d on the diameter, d strictly between u and v, c in the component of d). Then, u→v itself is optimal.
Now let's try all paths u→v of maximum (unweighted) length (there are O(n) of them). Notice that the required distance is also the maximum of dist(a,u), dist(v,b), dist(c,d) (d on the diameter, but not necessarily between u and v). If we precalculate the distance of each node from the root of its component and from a, b, we can get the maximum distance between a node and the nearest shop in O(1).
Hint 1You have to find the maximum total weight of two non-intersecting paths.
Hint 2Once again, choose any two paths and try to "improve" them.
Hint 3There are two cases to consider: - a path is the diameter and the other path lies completely in a component; - a path is a prefix of the diameter + a vertical path in the corresponding component, the other path is a suffix of the diameter + a vertical path in the corresponding component.
Can you solve them in O(n)?
SolutionYou have to find the maximum total weight of two non-intersecting paths. Notice that the facts stated previously hold even if weights are on nodes instead of edges.
There are two cases to consider: - a path is the diameter and the other path lies completely in a component; - a path is a prefix of the diameter + a vertical path in the corresponding component, the other path is a suffix of the diameter + a vertical path in the corresponding component.
Sketch of proof: suppose that the intersection of a chosen path i→j with the diameter is a path u→v (a,u,v,b in this order). The paths a→j, i→b, a→b are longer than i→j, so it's optimal to take one them instead of i→j if possible.
It's possible to solve both cases in O(n): - find the diameter of each component, pick the maximum; - precalculate the height of each component, the distance of each node from a, b, the prefix maximums pm(i) of dist(a,i)+height(i), the suffix maximums sm(i) of dist(i,b)+height(i), and find the maximum pm(i)+sm(i+1).
Hint 2The answer is -1
if there are ≥2 characters with an odd number of occurrences in the string. Otherwise, can you calculate the optimal final position of each character, like in 1430E - String Reversal?
Hint 3Once again, it's useless to swap equal characters. So, what's the relative position of equal characters? Which characters should be located in symmetrical positions (i.e. i,n−i+1)?
Hint 4The i-th leftmost occurrence and the i-th rightmost occurrence of a character c in the initial string should move to symmetrical positions in the final string. Let's consider such "symmetrical pairs": what's the optimal relative order of two pairs with distinct letters? What about the letter in the center of the string (if its length is odd)?
SolutionIf there are ≥2 characters with an odd number of occurrences in the string, you can't make a palindrome.
Since it's useless to swap equal characters, you know which pairs of characters will stay on symmetrical positions in the final string, i.e. the i-th leftmost occurrence and the i-th rightmost occurrence of any character c.
In the string acabcaaababbc
, for example, you can make these "symmetrical pairs": positions (1,10),(2,13),(3,8),(4,12),(6,7),(9,11). The character in position 5 should go in the center of the final string (i.e. position 7).
The symmetrical pairs have to be nested inside each other, in some order. Given two symmetrical pairs, which of them should be located outside the other one?
It turns out that the pair that contains the leftmost element should be located outside. In fact, if you want to reach xyyx, the initial configurations with x on the left (xxyy, xyxy, xyyx) require 2,1,0 moves respectively, while reaching yxxy requires 2,1,2 moves respectively.
So you can sort the symmetrical pairs by leftmost element and construct the array a such that ai is the final position of si in the palindromic string (in this case, [1,2,3,4,7,5,9,11,6,13,8,10,12]) and the result is the number of inversions of a.
Implementation (C++)
Hint 1Which balls can you put at the end?
Hint 2At the end, you have a ball with number n. For example, if it's white, you have to sort the remaining n−1 white balls and n black balls. How to calculate efficiently the cost required?
Hint 3Let dpi,j be the minimum cost required to sort the first i white balls (with a number from 1 to i) and the first j black balls (with a number from 1 to j). You need transitions in O(1).
Hint 4Re-read Proof 2 in this tutorial.
SolutionIt's easy to prove that the leftmost k balls in the final arrangement are the white balls with a number in [1,i] and the black balls with a number in [1,j] for some i,j such that i+j=k.
For fixed i,j, let dpi,j be the minimum cost (considering only such balls). If the last ball is white, you can move it immediately to the end (see Proof 2), and the cost is the number of l in the initial array such that
- l≤i−1 if the ball is white, l≤j if the ball is black
- pos(l)>pos(i)
Then you spend dpi−1,j to sort the rest of the array. You can calculate the cost similarly if the last ball is black.
Computing such transitions in O(1) can be done with simple prefix sums (for example, let psi,c,j be the number of balls with position ≥i, color c and value ≤j).
The result is dpn,n.
Implementation (C++)
Other problems
102694B - Dynamic Diameter
abc221_f
Conclusions
We've seen that a lot of problems where you have to swap adjacent elements can be tackled with greedy observations, such as looking at the optimal relative positions of the values in the final array; then, a lot of these problems can be reduced to "find the number of inversions" or similar.
Of course, suggestions/corrections are welcome. In particular, please share in the comments other problems where you have to swap adjacent elements.
I hope you enjoyed the blog!