显然如果一个叶子是黑色的,我们一定不会经过它。于是我们可以不断地剥叶子直到所有叶子均为白色,那么我们会经过起点到终点上的边恰好一次,其他边不同方向经过两次。
假设我们经过所有的边两次,那么每个节点会自动被反色度数次,不妨设第
i
i
i个点此时的颜色为
c
i
c_i
ci。起点到终点路径上的点除了终点以外都会少反色一次,因此如果起点到终点路径上(不包括终点)某个点的
c
i
c_i
ci为白可以减小
2
2
2的答案,
c
i
c_i
ci为黑答案不变,于是我们肯定是求一条
c
i
c_i
ci为白色的点最多的路径最优。注意到叶子节点的
c
i
c_i
ci一定为黑,因此方案是可以构造的。
实现只需要求出dfs两遍求出直径即可,时间复杂度
O
(
n
)
\mathcal O(n)
O(n)。
#include <bits/stdc++.h>
using namespace std;
vector <int> e[200005];
int d[200005];
bool ban[200005],val[200005];
int dis[200005];
int dfs(int x,int fa) {
dis[x]=dis[fa]+val[x];
int ans=x;
for(int i=0;i<e[x].size();i++)
if (e[x][i]!=fa&&!ban[e[x][i]]) {
int u=e[x][i];
int t=dfs(u,x);
if (dis[t]>dis[ans]) ans=t;
}
return ans;
}
char str[200005];
queue <int> q;
int main() {
int n;
scanf("%d",&n);
for(int i=1;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
d[x]++;d[y]++;
}
scanf("%s",str+1);
bool ok=0;
for(int i=1;i<=n;i++) {
val[i]=(str[i]=='W');
ok|=val[i];
}
if (!ok) {
puts("0");
return 0;
}
for(int i=1;i<=n;i++)
if (!val[i]&&d[i]<=1) q.push(i);
while (!q.empty()) {
int x=q.front();q.pop();
ban[x]=1;
for(int i=0;i<e[x].size();i++)
if (!ban[e[x][i]]) {
int u=e[x][i];
d[u]--;
if (!val[u]&&d[u]<=1) q.push(u);
}
}
int rt=0,s=-2;
for(int i=1;i<=n;i++)
if (!ban[i]) {
rt=i;
for(int j=0;j<e[i].size();j++)
if (!ban[e[i][j]]) val[e[i][j]]^=1;
s+=2;
}
for(int i=1;i<=n;i++)
if (!ban[i]) s+=val[i];
rt=dfs(rt,0);
int x=dfs(rt,0);
printf("%d\n",max(1,s-2*dis[x]));
return 0;
}