白魔法师(DFS&并查集)

传送门

思路: d f s dfs dfs搜索每个白色连通块,用数组 s z [ i ] sz[i] sz[i]纪录每个白色连通块的大小,

用数组 b l [ i ] bl[i] bl[i]记录结点 i i i属于那个白色连通块。然后遍历一遍结点,如果是白色,则直接取最大值,如果是黑色,则答案 = 1 + ∑ 与 u 相 连 的 结 点 v s z [ v ] =1+\sum\limits_{与u相连的结点v}sz[v] =1+uvsz[v]

时间复杂度: O ( V + E ) O(V+E) O(V+E)

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e5+5;
vector<int>e[N];
char s[N];
int n,sz[N],bl[N],id;//bl[i] 第i个结点归属那个白色连通块belong,sz[i]表示第i个白色连通块的大小
void dfs(int u,int fa){
    bl[u]=id;
    sz[id]++;
    for(auto v:e[u]){
        if(v==fa||s[v]=='B') continue;
        dfs(v,u);
    }
}
int main(){
    scanf("%d%s",&n,s+1);
    for(int i=1,u,v;i<n;i++){
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for(int i=1;i<=n;i++) if(s[i]=='W'&&!bl[i]) id++,dfs(i,0);//搜索每个白色连通块
    int ans=0;
    for(int i=1;i<=n;i++){
        if(bl[i]) ans=max(ans,sz[bl[i]]);
        else {//如果是黑色则加上它相连的白色连通块。
            int res=1;
            for(auto v:e[i]){
                if(s[v]=='W') res+=sz[bl[v]];
            }
            ans=max(ans,res);
        }
    }
            printf("%d\n",ans);
    return 0;
}

并查集做法:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e5+5;
vector<int>e[N];
char s[N];
int n,fa[N],sz[N],ans;
int find(int x){
    if(x!=fa[x]) fa[x]=find(fa[x]);
    return fa[x];
}
int main(){
    scanf("%d%s",&n,s+1);
    for(int i=1;i<=n;i++) fa[i]=i,sz[i]=1;//初始化
    for(int i=1,u,v;i<n;i++){
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
        if(s[u]==s[v]&&s[u]=='W'){//合并白色连通块
            u=find(u),v=find(v);
            if(u!=v) fa[u]=v,sz[v]+=sz[u];
        }
    }
    for(int i=1;i<=n;i++){
        if(s[i]=='W') ans=max(ans,sz[find(i)]);//注意sz 里的结点是白色连通块的根
        else {
            int res=1;
            for(auto v:e[i]){
                if(s[v]=='W') res+=sz[find(v)];
            }
            ans=max(res,ans);
        }
    }
            printf("%d\n",ans);
    return 0;
}