Monochrome Cat[ARC097D/F][思维题]

文章目录

题目

在这里插入图片描述
Atcoder

思路

最后差一点
首先发现黑色连通块显然不用去,删掉
然后所有叶子都是白色了
发现可以选择一条链走一次,剩下边都是两次
假设没有这条链 走完所有点 n n n 会花费 2 ∗ ( n − 1 ) + 白 点 2*(n-1)+白点 2(n1)+ 的代价
此时白点是往返后仍然为白点的点
再考虑链的情况
选择一段往返,那么会使得[起点+中间点]变色

白色变为黑色,少走一次+少按一下,代价-2
黑色变白色,少走一次但会多按一下
那么找覆盖最多白点的链即可
总代价:
2 ( n − 1 ) − 2 ∗ w 2(n-1)-2*w 2(n1)2w

代码

#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<climits>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
int read(){
	int f=0,x=0;char c=getchar();
	while(c<'0'||'9'<c){if(c=='-')f=1;c=getchar();}
	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return !f?x:-x;
}
#define mp make_pair
const int MAXN=100000;
vector<int> G[MAXN+5];
int n;
char str[MAXN+5];
int whi[MAXN+5],sw[MAXN+5],de[MAXN+5],f[MAXN+5],del;
void DFS1(int u,int fa){
	sw[u]=whi[u];
	for(int i=0;i<(int)G[u].size();i++){
		int v=G[u][i];
		if(v==fa) continue;
		DFS1(v,u),sw[u]+=sw[v];
	}
	return ;
}
void DFS2(int u,int fa){
	f[u]=whi[u];
	for(int i=0;i<(int)G[u].size();i++){
		int v=G[u][i];
		if(v==fa||!sw[v]) continue;
		DFS2(v,u);
		del=max(del,f[u]+f[v]);
		f[u]=max(f[u],f[v]+whi[u]);
	}
	return ;
}
int main(){
	n=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		G[u].push_back(v);
		G[v].push_back(u);
	}
	scanf("%s",str+1);
	int rt=-1;
	for(int i=1;i<=n;i++){
		whi[i]=(str[i]=='W'?1:0);
		if(whi[i])rt=i;
	}
	if(rt==-1){
		puts("0");
		return 0;
	}
	DFS1(rt,0);
	int ans=0,cnt=0;
	for(int u=1;u<=n;u++)
		if(sw[u]){
			for(int i=0;i<(int)G[u].size();i++){
				int v=G[u][i];
				if(sw[v]) de[u]++;
			}
			cnt++;
			whi[u]^=(de[u]&1);
			ans+=whi[u];
		}
	ans+=2*(cnt-1);
	DFS2(rt,0);
	ans-=2*del;
	printf("%d\n",ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值