12195. Chinar is a symbol of Azerbaijan
Do you know that every country has its own
symbolic tree? In Greece, it is the olive tree, in Japan – the sakura, in
Canada – the maple, in Australia – the golden wattle (mimosa), in Russia and
Finland – the birch.
The tree that holds a special place in
Azerbaijani folklore and has become a symbol of Azerbaijan is the Chinar (Plane
tree).
Since ancient times, the Chinar has been
surrounded by respect. Even the Romans knew and used its healing properties:
decoctions of its fruits stopped bleeding, treated burns and frostbites, and
infusions from its bark were used for snake bites. Nowadays, the bark of young
trunks is even used in cancer treatment, while decoctions and ointments made
from the fruits help with various ailments.
Imagine a huge Chinar tree grown in one of
the parks of Baku. It has n branches, and each branch is
colored either white or black. But such a multicolored appearance disrupts its
majestic harmony. Therefore, it was decided to repaint the tree so that it
becomes completely one color – either white or black.
Only one operation is available for
this: paint(v), where v is a chosen vertex
of the tree. This operation flips the color of all vertices u such
that on the shortest path from u to v, all
vertices have the same color (including the vertices u and v themselves).
For example, the tree on the left, after
applying the operation paint(3), will change its coloring as shown
on the right.
Your task is to determine the minimum
number of operations required to repaint the Chinar so that it becomes entirely
one color.
Input. The first line contains a single integer n (1 ≤ n ≤ 200000) – the number of vertices of the tree.
The second line contains n integers colori (0 ≤ colori ≤
1) – the colors of the
vertices. If colori = 0, the i-th
vertex is white; if colori = 1, it is black.
Each of the following n – 1 lines contains two integers ui and vi (1 ≤ ui, vi
≤ n, ui ≠ vi) – the edges of the tree. It is guaranteed
that all edges are distinct, so the graph contains no multiple edges.
Output. Print a single integer –
the minimum number of repaint operations required to make the Chinar completely
white or completely black.
Sample input 1 |
Sample output
1 |
10 0 0 0 1 1 1 0 0 0 0 1 2 1 3 1 4 2 5 2 6 5 7 6 8 4 9 4 10 |
2 |
|
|
Sample input 2 |
Sample output
2 |
5 0 0 0 1 1 1 2 1 3 2 4 3 5 |
1 |
tree
Algorithm analysis
If two vertices
of the same color are connected by an edge, they can be merged into one – the answer will
remain unchanged. Let’s introduce the concept of a connected component: two
vertices belong to the same connected component if they
·
have the same color, and
·
are connected by an edge.
Consider, for example, the
tree on the left. On the right, the graph of its connected components is shown.
If we apply, for example,
the operation paint(2), the component tree will be compressed:
The tree will be
painted in a single color if and only if, after such painting operations with
compression, exactly one component remains.
Let d be
the diameter of the component tree. The tree will be painted in a single color
if and only if the diameter of the tree becomes 0, since a diameter of 0 occurs
only in a tree consisting of a single vertex.
We now find such
a vertex that the length of the shortest path from it to any other vertex does
not exceed (d + 1) / 2. Such a vertex always exists, because otherwise
the diameter of the tree would be at least d + 1.
Finally, note
that by applying (d + 1) / 2 painting operations to this vertex, we can
paint the entire tree in a single color.
Algorithm implementation
Define the arrays.
vector<int> color, dist;
vector<vector<int> > g, g1;
vector<int> comp, used;
The function dfs1 performs a depth-first traversal of the
tree and partitions its vertices into connected components. Each vertex v
is assigned a component number id, which is stored in the array comp[v].
void dfs1(int v, int col, int id)
{
if (used[v]) return;
if (color[v] != col) return;
used[v] = 1;
comp[v] = id;
for (int to : g[v])
dfs1(to, col, id);
}
The function dfs2 performs a depth-first traversal of the
tree and computes the distances from the source to each vertex. For a vertex v,
this distance is stored in dist[v]. The current distance from the source
to vertex v is denoted by d.
void dfs2(int v, int d, int p = -1)
{
dist[v] = d;
for (int to : g1[v])
if (to != p) dfs2(to, d + 1, v);
}
The main part of the program. Read the input data and initialize the
arrays.
scanf("%d", &n);
color.resize(n
+ 1);
g.resize(n
+ 1);
comp.resize(n
+ 1);
used.assign(n
+ 1, 0);
for (i = 1; i <= n; i++)
scanf("%d", &color[i]);
Read and construct an undirected tree.
for (i = 0; i < n - 1; i++)
{
scanf("%d %d", &a, &b);
g[a].push_back(b);
g[b].push_back(a);
}
Partition the vertices of the tree into components. The total number of
components is cnt. The components are numbered starting from 1.
cnt = 0;
for (i = 1; i <= n; i++)
if (!used[i])
{
cnt++;
dfs1(i, color[i], cnt);
}
Construct the graph g1 – the component graph (the compressed tree).
g1.resize(cnt
+ 1);
for (v = 1; v <= n; v++)
for (int to : g[v])
if (comp[v] != comp[to])
g1[comp[v]].push_back(comp[to]);
Compute the diameter of the component graph.
dist.resize(cnt
+ 1);
Start a depth-first search from vertex 1 and fill the array dist,
which stores the shortest distances from this vertex.
dfs2(1, 0,
-1);
Vertex a is the one located at the maximum distance from vertex 1.
a =
max_element(dist.begin(), dist.begin() + cnt + 1) - dist.begin();
Start a depth-first search from vertex a and fill the array dist
again.
dfs2(a, 0,
-1);
Vertex b is the one farthest from a. The distance between a
and b is the diameter of the component graph.
b =
max_element(dist.begin(), dist.begin() + cnt + 1) - dist.begin();
Print the answer.
printf("%d\n", (dist[b] + 1) / 2);