天梯赛 · 并查集

(1)朴素并查集:=》只判连通

cpp 复制代码
int p[N];              // 存储每个点的祖宗节点

// 查找 + 路径压缩(核心)
int find(int x)
{
    if (p[x] != x) 
        p[x] = find(p[x]);  // 路径直接挂到根节点
    return p[x];
}

// 初始化:每个点自己是根
for (int i = 1; i <= n; i ++ ) 
    p[i] = i;

// 合并 a 和 b 所在集合
p[find(a)] = find(b);

(2)带集合大小的并查集:=》统计集合元素个数(连不连通 + 集合多大)

cpp 复制代码
int p[N], size[N];    
// p[]:存储每个点的祖宗节点
// size[]:只有祖宗节点有效,表示当前集合的元素数量

// 查找 x 的根节点 + 路径压缩
int find(int x)
{
    if (p[x] != x) 
        p[x] = find(p[x]);
    return p[x];
}

// 初始化:每个点自己是根,集合大小为 1
void init(int n)
{
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        size[i] = 1;
    }
}

// 合并 a 和 b 所在的集合
void merge(int a, int b)
{
    int fa = find(a);
    int fb = find(b);
    if (fa != fb)
    {
        // 先更新集合大小,再修改父节点(顺序不能变)
        size[fb] += size[fa];
        p[fa] = fb;
    }
}

(3)维护到祖宗节点距离的并查集:=》维护点到根的距离/关系(连不连通 + 两点之间距离 / 关系)

cpp 复制代码
int p[N], d[N];        
// p[x]:存储节点 x 的父节点
// d[x]:存储 x 到其父节点 p[x] 的距离/权值(find后表示x到根节点的距离)

// 查找 x 的根节点 + 路径压缩 + 维护距离
int find(int x)
{
    if (p[x] != x)
    {
        // 先递归找到根节点 u
        int u = find(p[x]);
        // 更新 x 到根节点的距离
        d[x] += d[p[x]];
        // 路径压缩:直接把 x 挂到根节点上
        p[x] = u;
    }
    return p[x];
}

// 初始化:每个节点自己是根,到父节点距离为 0
void init(int n)
{
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        d[i] = 0;
    }
}

// 合并 a 和 b 所在集合(根据题目自定义 distance)
void merge(int a, int b, int distance)
{
    int fa = find(a);
    int fb = find(b);
    if (fa != fb)
    {
        p[fa] = fb;
        d[fa] = distance;  // 核心:设置根 fa 到根 fb 的权值
    }
}

L2-024 部落

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+10;
int p[N];
int find(int x){
    if(p[x]!=x){
        p[x]=find(p[x]);
    }
    return p[x];
}
int main(){
    int n;
    int maxnum = 0;
    if(!(cin>>n)) return 0;
    for(int i = 0;i<N;i++) p[i] = i;
    for(int i = 0 ;i <n;i++){
        int k;
        if(!(cin>>k)) return 0;
        vector<int> a(k);
        for(int j = 0;j<k;j++ ){
            int x;
            cin>>x;
            if(x>maxnum) maxnum = x;
            a[j] = x;
        }
        if(k<2) continue;
     
        for(int j = 0;j<k-1;j++){
            int x = find(a[j]);
            int y = find(a[j+1]);
            if(x!=y){
                p[y] = x;
            }
        }
    }
    set<int> mp;
    //p[i] = 父节点,不一定是根
    //find(i) = 一定是根
    for(int i = 1;i<=maxnum;i++){
        mp.insert(find(i));
    }
    cout<<maxnum<<" "<<mp.size()<<endl;
    int q;
    cin>>q;
    while(q--){
        int x,y;
        cin>>x>>y;
        if(find(x)==find(y)) cout<<"Y\n";
        else cout<<"N\n";
    }
    return 0;
}

L3-003 社交集群

cpp 复制代码
#include<iostream>
#include<map>
#include<set>
using namespace std;
int f[1005], p[1005];
map<int, int> mp;
multiset<int, greater<int>> st;
int find(int x){
    if(f[x]==x) return f[x];
    return f[x]=find(f[x]);
}
void merge(int x, int y){
    int a=find(x), b=find(y);
    if(a!=b) f[b]=a;
}
int main(){
    for(int i=0; i<1005; i++) f[i]=i;
    char _;
    int n, k, h;
    cin >> n;
    for(int i=1; i<=n; i++){
        cin >> k >> _ >> p[i];
        while(--k){
            cin >> h;
            merge(p[i], h);
        }
    }for(int i=1; i<=n; i++) mp[find(p[i])]++;
    for(auto q:mp) st.insert(q.second);
    cout << st.size() << "\n" << *st.begin();
    st.erase(st.begin());
    for(auto q:st) cout << ' ' << q;
    cout << "\n";
}
相关推荐
洛水水2 分钟前
【力扣100题】41.爬楼梯
算法·leetcode·职场和发展
sheeta19981 小时前
LeetCode 每日一题笔记 日期:2026.05.13 题目:1674. 使数组互补的最少操作次数
笔记·算法·leetcode
liulilittle2 小时前
TCP UCP v1.0:BBR 的非破坏性约束层
网络·c++·网络协议·tcp/ip·算法·c·通信
每天回答3个问题2 小时前
LeetCodeHot100|回溯算法、46.全排列、78.子集、17.电话号码的字母组合
算法·深度优先·回溯
YL200404262 小时前
038翻转二叉树
数据结构·leetcode
Liangwei Lin3 小时前
LeetCode 287. 寻找重复数
算法·leetcode·职场和发展
OCR_133716212754 小时前
护照OCR校验位技术解析:从算法逻辑到工程落地,筑牢证件核验安全线
人工智能·算法
Hello.Reader4 小时前
算法基础(十三)——随机算法为什么有时主动引入随机性
java·数据库·算法
likerhood4 小时前
ConcurrentHashMap底层数据结构和面试常见问题
java·数据结构·面试·hashmap
老鱼说AI4 小时前
现代 LangChain 开发指南:从 LCEL 原理到企业级 RAG 与 Agent 实战
java·开发语言·人工智能·深度学习·神经网络·算法·机器学习