codeforces - 734E - Anton and Tree(图论 树)
LINK:http://codeforces.com/contest/734/problem/E
题意:
给一棵树,点被染成了黑白二色,每次操作可以翻转相邻的同色点的颜色,问最少多少次操作能把整棵树染成一个颜色。
解法:
当天没去看..被剧透了,帮人把结论证明了一遍:把相邻同色的点缩点之后树的直径的一半就是答案。
对每个不是直径上的分支,都能在分支节点染色,从而合并进树的直径上进行染色,所以只用挑一个颜色染完直径即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 2000010;
bool vis[N] = {0};
int dp[N] = {0}, col[N], head[N], tot = 0;
int st = 1, deeep = 0;
struct edge {
int v, next;
} edge[N];
void addedge(int u, int v) {
edge[tot].v = v;
edge[tot].next = head[u];
head[u] = tot++;
}
int dfs(int u, int dep) {
if(dep > deeep) {
deeep = dep;
st = u;
}
int ret = dep, tmp;
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if(vis[v])continue;
vis[v] = 1;
if(col[v] == col[u]) {
ret = max(dfs(v, dep), ret);
} else {
ret = max(dfs(v, dep + 1), ret);
}
}
return ret;
}
int main() {
int a, b;
int n;
memset(head , -1, sizeof head);
cin >> n;
for(int i = 1; i <= n; i++) {
scanf("%d", &col[i]);
}
for(int i = 1; i < n; i++) {
scanf("%d%d", &a, &b);
addedge(a, b);
addedge(b, a);
}
dfs(1, 0);
memset(vis, 0, sizeof vis);
int ans = dfs(st, 0) + 1;
cout << ans / 2 << endl;
return 0;
}