Editorial for COCI '19 Contest 3 #4 Lampice
Submitting an official solution before solving the problem yourself is a bannable offence.
The first subtask can be solved in multiple ways. We will describe the solution using hashing which will be useful for the final subtask. Let's root the tree in a node . We are interested in all palindromic segments with one end in node 
. For every node 
, we will calculate two values:
Where  is an array of colors on the path from 
 to 
 (
, 
) and 
 is the value of the hash basis. These two values can be determined using a single DFS traversal of our tree. The path from 
 to 
 is a palindromic segment if 
 holds. If we root the tree in every node and apply this procedure, we will cover all cases. The complexity of this algorithm is 
.
The second subtask is a classic, well-known problem of finding the longest palindromic substring which can be solved using Manacher's algorithm.
The solution for the third subtask is quite similar to the solution of the second subtask. The only difference is that we must apply Manacher's algorithm on a path between every pair of leaves.
We will begin our solution for the whole problem with the following observation: If there exists a palindromic segment of length , then there exists a palindromic segment of length 
. Therefore, we can use binary search on even and odd lengths to find the longest palindromic segment.
But, how do we check if a palindromic segment of fixed length exists in a given tree? To answer that question, we will first solve an easier version of that problem – we will check if there is a palindromic segment of a fixed length that contains the root of our tree, node .
In a rooted tree, a path between two nodes  and 
 consists of two tree branches, where the length of path on one branch is greater or equal to the length on the other branch. We will divide the path between 
 and 
 into three parts: path from 
 to 
, path from 
 to the root and path from the root to 
, where 
 is chosen such that the lengths 
 and 
 are equal. Note that 
 is uniquely defined by the node 
, since we only care about palindromes of fixed size. In order to check whether the path from 
 to 
 is a palindromic segment, it is enough to check the following:
- (1) Path from 
to
is a palindrome (depicted in red)
 - (2) Colors from 
to
are the same as colors from
to
(depicted blue).
 

For each node of the tree, we will calculate the values  and 
 in advance in the same manner as it was described in the solution of the first subtask. The first check is simply done by comparing 
 and 
. The second check can be done by comparing the values:
- (3) 
, where
is the parent of node
and
is the depth of node
.
 
Now we know how to efficiently check whether the path from  to 
 is a palindromic segment, but that is still not enough because there are 
 such pairs 
. Let's try to observe the problem from another angle: If we fix 
, is there (at least) one 
 that satisfies all the conditions? Let 
 be a set of hashes in which we will insert values 
 of all nodes 
 of our tree. Then, for a fixed 
, we can simply check condition (1) and we can check condition (3) by finding the corresponding value in 
. We can assume that the complexity of all operations with 
 is constant if we use a hash table (
std::unordered_set in C++, for example). The complexity of the whole check is therefore .
Note: during implementation you need to make sure that the lowest common ancestor of nodes in  and 
 is the root node 
.
Now that we know whether a palindromic segment of certain length which passes through the root  exists, we can use centroid decomposition. If we perform this check for every decomposed subtree with the centroid as a root, we will cover all the cases. With centroid decomposition and a binary search, we end up with an algorithm of complexity 
.
Comments