给定 (n) 个点的树,每个点有黑白色。
猫猫可以空降在任意位置,若当前位置为 (u),可以选择以下两项之一进行:
- 反转 (u) 的颜色。
- 移动到相邻点 (v),反转 (v) 的颜色。
求变为全黑的最小操作次数。(nle 10^5)。
把黑叶子删完,此时叶子都是白的,都需要经过。
可以从某个叶子开始,依次经过每个叶子,操作次数是路径长度+中途踩一踩修整贡献。
回路显然会把每条边经过恰好两遍,把回路的贡献算出来,去掉贡献最大的一条路径,也就是直径,用树形 dp 找出直径长度即可。
时空复杂度 (O(n))。
#include<bits/stdc++.h>
using namespace std;
const int N = 100003;
template<typename T>
void read(T &x){
int ch = getchar(); x = 0; bool f = false;
for(;ch < '0' || ch > '9';ch = getchar()) f |= ch == '-';
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
} template<typename T>
bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
int n, cnt, ans, u[N], v[N], deg[N], head[N], to[N<<1], nxt[N<<1]; char str[N];
void add(int u, int v){to[++cnt] = v; nxt[cnt] = head[u]; head[u] = cnt;}
int q[N], fr, re, dis, val[N], dep[N]; bool vis[N];
void dfs(int x, int f = 0){
for(int i = head[x];i;i = nxt[i]) if(!vis[to[i]] && to[i] != f){
dfs(to[i], x);
chmax(dis, dep[x] + dep[to[i]] + val[x]);
chmax(dep[x], dep[to[i]]);
} dep[x] += val[x];
}
int main(){ //freopen("a.in", "r", stdin);
read(n);
for(int i = 1;i < n;++ i){
read(u[i]); read(v[i]);
add(u[i], v[i]); add(v[i], u[i]);
++ deg[u[i]]; ++ deg[v[i]];
} scanf("%s", str+1);
for(int i = 1;i <= n;++ i) if(deg[i] == 1 && str[i] == 'B') q[re++] = i;
while(fr < re){
int u = q[fr++]; vis[u] = true;
for(int i = head[u];i;i = nxt[i]) if(!vis[to[i]]){
-- deg[to[i]];
if(deg[to[i]] == 1 && str[to[i]] == 'B')
q[re++] = to[i];
}
} cnt = 0; memset(head, 0, sizeof head);
for(int i = 1;i < n;++ i)
if(!vis[u[i]] && !vis[v[i]]){
add(u[i], v[i]); add(v[i], u[i]);
} ans = cnt;
for(int i = 1;i <= n;++ i)
if(!vis[i] && (deg[i] & 1) == (str[i] == 'B')){
++ ans; val[i] = 2;
}
for(int i = 1;i <= n;++ i) if(!vis[i]){dfs(i); break;}
printf("%d
", ans - dis);
}