白魔法师(牛客小白月赛25 图、并查集)

白魔法师

链接:https://ac.nowcoder.com/acm/contest/5600/C

题目描述
你是一个白魔法师。
现在你拿到了一棵树,树上有 n n 个点,每个点被染成了黑色或白色。
你可以释放一次魔法,将某个点染成白色。(该点不一定是黑色点,也可以是白色点)
现在释放魔法后要保证最大的白色点连通块尽可能大。请求出最大白色连通块的大小。
注:所谓白色连通块,指这颗树的某个连通子图,上面的点全部是白色。
输入描述:
第一行输入一个正整数 n n ,代表树的顶点数量。( 1 n 100000 1\leq n \leq 100000
第二行输入一个长度为 n n 的、仅由’W’和’B’组成的字符串,第 i i 个点为’W’代表该点为白色,'B’代表该点为黑色。
接下来的 n 1 n-1 行,每行输入两个正整数 x x y y ,代表 x x 点和 y y 点有一条边连接。( 1 x , y n 1\leq x,y\leq n
输出描述:
一个正整数,代表施放魔法后,最大的白色连通块的大小。
输入
4
WBBW
1 2
2 3
3 4
输出
2

思路:
有一次机会把一个点染成白色的,那么肯定要把黑点染成白色,这样的话与这个黑点相邻的所有白连通块就能连在一起形成一个更大的连通块了。
先用并查集预处理所有的白色点,求出白色连通块的大小,然后枚举黑色点,求与黑色点直接相邻的白色连通块的总的大小即可。注意特判全是白色点的情况。

Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n;
string s;
vector<int> e[N];
int f[N], cnt[N];
void init()
{
    for (int i = 0; i <= n; i++)
        f[i] = i;
}
int findd(int x)
{
    if (f[x] != x)
        f[x] = findd(f[x]);
    return f[x];
}
bool mergee(int x, int y)
{
    int fx = findd(x), fy = findd(y);
    if (fx == fy)
        return true;
    f[fy] = fx;
    cnt[fx] += cnt[fy];
    return false;
}
int main()
{
    cin >> n >> s;
    init();
    for (int i = 1; i <= n; i++)
        cnt[i] = (s[i - 1] == 'W');
    int u, v;
    for (int i = 1; i < n; i++)
    {
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
        if (s[u - 1] == 'W' && s[v - 1] == 'W')
            mergee(u, v);
    }
    if (cnt[findd(1)] == n)
    {
        cout << n << endl;
        return 0;
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        int sum = 1;
        if (s[i - 1] == 'B')
            for (auto j : e[i])
                sum += cnt[findd(j)];
        ans = max(ans, sum);
    }
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44169557/article/details/106220842