ARC097F Monochrome Cat

给定 (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);
}
原文地址:https://www.cnblogs.com/AThousandMoons/p/14545740.html