5.18 每日一题题解

白魔法师

涉及知识点:

  • 图论/并查集

solution:

  • \(这道题目和2020寒假训练营1的F题是一个套路(毕竟出题人也是同一个人\)
  • \(简述一种并查集做法:\)
  • \(如果并查集不知道是啥,看样子咕了好多次每日一题了哦!\)
  • \(我们先预处理所有相邻的白色节点\)
  • \(对于每个白色节点,通过深搜计算所有和其联通的白色节点个数\)
  • \(并将该联通的白色节点通过并查集记为同一个集合\)
  • \(题目要求,我们只可以将一个节点,变成白色\)
  • \(所以我们枚举每一个黑色节点,假设将这个节点染成白色\)
  • \(将这个黑色节点变成白色产生的最大联通白色节点个数是多少?\)
  • \(其实就等于这个黑色节点相连的所有白色节点对应的集合 + 1\)
  • \(实在不理解上图!\)

std:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5+5;
int a[maxn],b[maxn],f[maxn],flag[maxn];
vector<int> v[maxn];
int find(int x){
    return f[x] == x ? x : (f[x] = find(f[x]));
}
void unite(int x,int y){
    x = find(x),y = find(y);
    if(x != y)
        f[y] = x;
}
int dfs(int x,int fa){
    int cnt = 1;
    for(int i=0;i<v[x].size();i++){
        if(flag[v[x][i]] == 0 && a[v[x][i]] == 1){
            unite(x,v[x][i]);
            flag[v[x][i]] = 1;
            cnt += dfs(v[x][i],x);
        }
    }
    return cnt;
}
int main()
{
    int n;
    char c;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        cin>>c;
        f[i] = i;
        if(c == 'W')a[i] = 1;
    }
    for(int i=1;i<n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    int ans = 0;
    for(int i=1;i<=n;i++){
        if(flag[i] == 0 && a[i] == 1){
            flag[i] = 1;
            int x = dfs(i , 0);
            int y = find(i);
            b[y] = x ;
            ans = max(ans,x);
        }
    }
    for(int i=1;i<=n;i++){
        if(a[i] == 0){
            int cnt = 1;
            for(int j=0;j<v[i].size();j++){
                if(a[v[i][j]] == 1){
                    cnt += b[find(v[i][j])];
                }
            }
            ans = max(ans ,cnt);
        }
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/QFNU-ACM/p/12909707.html