CF734E:Anton and Tree(缩点 & 直径)

探讨在一棵带有两种颜色的树形图中,通过特定操作使得所有节点颜色统一所需的最少步骤。文章介绍了一种有效的算法,通过节点压缩并求解树的直径来确定最优解。

E. Anton and Tree
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Anton is growing a tree in his garden. In case you forgot, the tree is a connected acyclic undirected graph.

There are n vertices in the tree, each of them is painted black or white. Anton doesn't like multicolored trees, so he wants to change the tree such that all vertices have the same color (black or white).

To change the colors Anton can use only operations of one type. We denote it as paint(v), where v is some vertex of the tree. This operation changes the color of all vertices u such that all vertices on the shortest path from v to u have the same color (including v and u). For example, consider the tree

and apply operation paint(3) to get the following:

Anton is interested in the minimum number of operation he needs to perform in order to make the colors of all vertices equal.

Input

The first line of the input contains a single integer n (1 ≤ n ≤ 200 000) — the number of vertices in the tree.

The second line contains n integers colori (0 ≤ colori ≤ 1) — colors of the vertices. colori = 0 means that the i-th vertex is initially painted white, while colori = 1 means it's initially painted black.

Then follow n - 1 line, each of them contains a pair of integers ui and vi (1 ≤ ui, vi ≤ n, ui ≠ vi) — indices of vertices connected by the corresponding edge. It's guaranteed that all pairs (ui, vi) are distinct, i.e. there are no multiple edges.

Output

Print one integer — the minimum number of operations Anton has to apply in order to make all vertices of the tree black or all vertices of the tree white.

Examples
input
11
0 0 0 1 1 0 1 0 0 1 1
1 2
1 3
2 4
2 5
5 6
5 7
3 8
3 9
3 10
9 11
output
2
input
4
0 0 0 0
1 2
2 3
3 4
output
0
Note

In the first sample, the tree is the same as on the picture. If we first apply operation paint(3) and then apply paint(6), the tree will become completely black, so the answer is 2.

In the second sample, the tree is already white, so there is no need to apply any operations and the answer is 0.


题意:一棵树有两种颜色,每次操作可以将一个节点及其所在的联通块变色,问使整棵树变成同一种色要几次操作。

思路:缩点,求树的直径d,(d+1)/2就是答案,即从最长链的中间开始变色。

# include <bits/stdc++.h>
# define pb push_back
using namespace std;
const int maxn = 2e5+30;
vector<int>v[maxn], s[maxn];
int ans=0, a[maxn], cnt=0, vis[maxn], h[maxn], fa[maxn];
void dfs(int cur, int tag)
{
    vis[cur] = 1;
    fa[cur] = tag;
    for(auto to : v[cur])
    {
        if(vis[to] || a[to] != a[cur] ) continue;
        vis[to] = 1;
        dfs(to, tag);
    }
}

void dfs2(int cur, int pre)
{
    int mx=0, mmx=0;
    for(auto to : s[cur])
    {
        if(to == pre) continue;
        dfs2(to, cur);
        mx = max(mx, h[to]+1);
        if(mx > mmx) swap(mx, mmx);//维护两个最深的儿子。
    }
    h[cur] = mmx;
    ans = max(ans, mx+mmx);
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; ++i) scanf("%d",&a[i]);
    for(int i=1; i<n; ++i)
    {
        int a, b;
        scanf("%d%d",&a,&b);
        v[a].pb(b), v[b].pb(a);
    }
    for(int i=1; i<=n; ++i)
        if(!vis[i])
            dfs(i, ++cnt);
    for(int i=1; i<=n; ++i)
        for(auto j : v[i])
            if(a[j] != a[i]) s[fa[i]].pb(fa[j]);
    dfs2(1, 0);
    printf("%d\n",(ans+1)/2);
    return 0;
}



06-02
&lt;think&gt;好的,用户现在在问Codeforces problem734E的解决方案或解释。我需要先回忆一下这道题的具体内容。题目编号734E对应的是Codeforces上的一个题目,通常这类题目会有具体的名称和问题描述。不过根据用户提供的引用内容,之前的引用似乎提到了其他问题,比如742B,涉及位运算和异或操作。但用户现在明确询问的是734E,所以需要转向这个题号的内容。首先,我需要确认734E的题目内容。Codeforces的题目734E的标题通常是&ldquo;Antonand Tree&rdquo;,这题涉及树的结构和图论中的连通性处理。题目大意是给定一棵树,每个节有黑色或白色,每次操作可以翻转一个颜色相同的连通区域的颜色,问最少需要多少次操作让整棵树变成同一种颜色。 接下来,我需要分析这个问题。解决这类问题通常需要找到树中的最长路径,也就是直径。因为每次操作可以翻转整个同色连通区域,所以关键在于如何将相邻的相同颜色节合并,形成更大的连通块。然后,将问题转化为处理合并后的树的直径,所需的最小操作次数通常是直径长度的一半,向上取整。用户可能需要具体的解决步骤,比如如何通过两次BFS或DFS找到树的直径,或者如何预处理颜色相同的连通块。此外,可能还需要解释为什么直径决定了最小操作次数,以及具体的实现方法,比如构建后的树,然后计算其直径。在回答时,需要结构清晰,分步骤解释。可能还需要提供代码示例,比如用Python或C++实现的解法。同时,根据用户之前的引用,他们可能对位运算或其他算法感兴趣,但734E主要涉及树和图论,需要调整回答内容。 用户可能还会关心时间复杂度的分析,或者如何优化算法。例如,两次BFS的时间复杂度是线性的,适合处理大范围的树结构。此外,需要验证思路的正确性,确保每一步的逻辑正确,比如合并同色节后的树结构是否确实将问题转化为求直径的问题。 最后,生成相关问题,比如如何找到树的直径,如何处理连通块,或者类似的问题推荐,帮助用户进一步巩固相关知识。&lt;/think&gt;### Codeforces 734E Anton and Tree 问题解析 **题目概述** 给定一棵$n$个节的树,每个节为黑色或白色。每次操作可以选择一个颜色相同的连通区域,翻转其颜色(黑&rarr;白,白&rarr;黑)。求使整棵树变为单一颜色的最小操作次数[^4]。 --- ### 关键思路 1. **连通块合并** 将相邻同色节视为一个超级节),形成新的树结构。此时新树中相邻节颜色必然不同。 **示例**:原树为`黑-黑-白-白-黑`,合并后变为`黑-白-黑`。 2. **树直径与操作次数** 新树的直径决定了最小操作次数。设直径为$d$,则答案为$\lfloor \frac{d+1}{2} \rfloor$。 **原理**:每次操作可消除直径的一层颜色差异,最终在$\lfloor d/2 \rfloor$步内完成[^1]。 --- ### 算法步骤 1. **构建后的树** - 使用DFS/BFS遍历原树,合并同色连通块。 - 记录合并后的边(仅连接不同颜色块)。 2. **求树的直径** - **两次BFS法**: - 第一次BFS找到最远节$u$ - 第二次BFS从$u$出发找到最远节$v$,路径$u&rarr;v$即为直径。 --- ### 代码实现(Python) ```python import sys from collections import deque def main(): sys.setrecursionlimit(1 &lt;&lt; 25) n = int(sys.stdin.readline()) color = list(map(int, sys.stdin.readline().split())) adj = [[] for _ in range(n)] for _ in range(n-1): u, v = map(int, sys.stdin.readline().split()) adj[u-1].append(v-1) adj[v-1].append(u-1) # 构建后的边 new_edges = [[] for _ in range(n)] visited = [False] * n def dfs(u, parent): visited[u] = True for v in adj[u]: if v == parent: continue if color[u] == color[v]: dfs(v, u) else: new_edges[u].append(v) dfs(0, -1) # BFS找最远节 def bfs(start): q = deque() dist = [-1] * n dist[start] = 0 q.append(start) max_dist = 0 far_node = start while q: u = q.popleft() for v in new_edges[u]: if dist[v] == -1: dist[v] = dist[u] + 1 if dist[v] &gt; max_dist: max_dist = dist[v] far_node = v q.append(v) return far_node, max_dist u, _ = bfs(0) v, d = bfs(u) print((d + 1) // 2) if __name__ == &quot;__main__&quot;: main() ``` --- ### 复杂度分析 - **时间**:$O(n)$,两次BFS和DFS均为线性时间。 - **空间**:$O(n)$,存储邻接表和距离数组。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值