白魔法师 & maki和tree - 并查集统计树上信息

maki和tree

魔法师

都是并查集来求的

有一棵树,树上每一个点有一个颜色,白色或者黑色,然后可以把一个黑色变成白色。求白色的最大连通块

把每一个黑色点看成并查集的根节点,然后与这个黑色点连通的白色点都是这个并查集里面的点

那么并查集最大值就是答案

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int N = 1e5 + 5;
std::vector<int> G[N];
char s[N];
int fa[N], rak[N], siz[N];
int find(int x){
    return fa[x] == x ? x : find(fa[x]);
}
void unit(int x, int y){
    x = find(x), y = find(y);
    if(x != y){
          if(rak[x] < rak[y]){
              fa[x] = y;
            rak[y] += rak[x] + 1;
        }else{
            fa[y] = x;
            rak[x] += rak[y] + 1;
        }
    }
}
int main(){
    int n;
    scanf("%d", &n);
    scanf("%s", s + 1);
    for(int i = 1; i <= n; i++)fa[i] = i;
    for(int i = 1; i < n; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
        if(s[u] == s[v] && s[v] == 'W')unit(u, v);
    }
    for(int i = 1; i <= n; i++)
        if(s[i] == 'W')siz[i] = rak[find(i)] + 1;
    int ans = 0;
    for(int i = 1; i <= n; i++){
        if(s[i] == 'B'){
            int sum = 1;
            for(int j = 0; j < G[i].size(); j++){
                if(s[G[i][j]] == 'W')sum += siz[G[i][j]];
            }
            ans = max(ans, sum);
        }
    }
    printf("%d\n", ans == 0 ? n : ans);
    return 0;
}

maki和tree是求路径有多少条
我的题解

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn = 1e5+5;
const int inf = 0x3f3f3f3f;
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return f*x;
}
char s[maxn];
std::vector<int> G[maxn];
ll sum,t1,t2,ans;
void dfs(int p,int fa){
    if(s[p] == 'B')return;
    sum++;
    for(int i = 0; i < G[p].size(); i++)
        if(G[p][i] != fa)dfs(G[p][i],p);
}
int main(){
    int n = read();
    scanf("%s",s+1);
    for(int i = 1; i < n; i++){
        int x,y;
        x = read(),y = read();
        G[x].push_back(y);
        G[y].push_back(x);
    }
    for(int i = 1; i <= n; i++){
        t1 = 0,t2 = 0;//t1黑点的所有点延续下去,连续白色的个数
        if(s[i] == 'B'){
            for(int j = 0; j < G[i].size(); j++){
                sum = 0;//表示与黑色点连接的一个点延续下去,连续白色的个数
                dfs(G[i][j],G[i][j]);
                ans += sum;
                t1 += sum;
                t2 += sum * sum;
            }
            ans += (t1 * t1 - t2)/2;
        }
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2020-05-18 13:32  Emcikem  阅读(162)  评论(0编辑  收藏  举报