Nowcoder 106 C.Professional Manager(统计并查集的个数)

题意:

给出四种操作:

1. 合并u,v两棵树

2. 从u所在的集合中删除u

3. 询问u所在集合有多少颗树

4. 询问 u,v是否在同一个集合

分析:

对于删除操作, 只要新开一个点代替原来的点即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5e4;
int f[maxn], cnt[maxn], id[maxn]; 
//id是负责记录这个点是原来的点还是删除操作后新开的点
void init(){
    for(int i = 0; i < maxn; i++){
        f[i] = i;
        cnt[i] = 1;
        id[i] = i;
    }
}
int find(int x){
    if(x == f[x]) return x;
    else {
        return f[x] = find(f[x]);
    }
}
void merge(int u, int v){
    int a = find(u);
    int b = find(v);
    if(a != b){
        f[b] = a;
        cnt[a] += cnt[b];
        cnt[b] = 0;
    }
}
int n, q;
int main(){
//    freopen("1.txt","r", stdin);
    ios::sync_with_stdio(false);
    int T;
    cin >> T;
    for(int kase = 1; kase <= T; kase++){
        cout << "Case #" << kase << ":
";
        init();
        cin >> n >> q;
        int tot = n;
        for(int i = 0; i < q; i++){
            int op, u, v;
            cin >> op;
            switch(op){
                case 1:{
                    cin >> u >> v;
                    merge(id[u],id[v]);
                    break;
                }
                case 2:{//删除操作,另开一个点代替原来的点
                    cin >> u;
                    int p = find(id[u]);
                    cnt[p]--;
                    id[u] = ++tot;
//                    f[id[u]] = id[u];
                    break;
                }
                case 3:{
                    cin >> u;
                    cout << cnt[find(id[u])] << "
";
                    break;
                }
                case 4:{
                    cin >> u >> v;
                    if(find(id[u]) == find(id[v])){
                        cout << "YES
";
                    }else cout << "NO
";
                }
            }
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Jadon97/p/9007212.html