首页 > 其他分享 >并查集的启发式合并

并查集的启发式合并

时间:2022-10-16 10:45:15浏览次数:72  
标签:int 查集 合并 集合 vec 启发式 find

背景:遇到一个题要用到,所以总结一下

概述

启发式合并的本质其实就是把size小的集合合并到size大的集合里面
一般在需要查询并查集内元素或合并集合的时候可能会用到启发式合并
比如合并 \([4,5,2,1]\) 和 \([1,2,4,6,8,9]\) 两个集合,我们选择遍历第一个集合合并到第二个集合里

代码以及分析

void merge(vector<int>&a, vector<int>&b) {
	if (a.size() > b.size()) for (int x : b) a.push_back(x);
	else for (int x : a) b.push_back(x);
}

在这里一个vector就表示一个集合

由于是从小集合合并到大集合,每次合并至少扩大一倍size,所以每个元素最多会被操作 \(O(logN)\) 次

例题

既然清楚了启发式合并的核心思想,那么我们来练一道题加深对它的理解
启发式合并例题

这道题说白了的话就是根据题目中所给的询问建边合并集合,边的权值就是建立完成的时间,问每个元素第一次合并到1所在的集合需要花费多少时间

思路

我们只需要在每次询问进行启发式合并并更新合并的信息即可
最后合并到只剩1所在的集合,时间复杂度 \(O(NlogN)\)

代码

//                  ξ†(ᗜ ˰ ᗜ)†ξ
//           去吧,鸭鸭,把希儿和AC都带回来!
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 2e5 + 5;
int res[N];
int fa[N];
int sz[N];
vector<int> vec[N];
int find(int x){
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void merge(int a,int b,int t){
    a = find(a);
    b = find(b);
    if(a == b) return;
    if(a == find(1)){
        for(auto x : vec[b]){
            res[x] = t;
        }
    }
    else if(b == find(1)){
        for(auto x : vec[a]){
            res[x] = t;
        }
    }
    //更新操作
    if(sz[a] < sz[b]) swap(a,b);
    sz[a] += sz[b];
    fa[b] = a;
    for(auto x : vec[b]){
        vec[a].push_back(x);
    }
    // 启发式合并
}
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
    }
inline void print(int x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9)
        print(x/10);
        putchar(x%10+'0');
    }
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++){
        fa[i] = i;
        sz[i] = 1;
        vec[i].push_back(i);
        res[i] = -1;
    }
    res[1] = 0;
    int m1,m2;
    cin >> m1 >> m2;
    while(m1--){
        int a,b;
        cin >> a >> b;
        merge(a,b,0);
    }
    for(int i = 1; i <= m2; i++){
        int a,b;
        cin >> a >> b;
        merge(a,b,i);
    }
    for(int i = 1; i <= n; i++){
        cout << res[i] << endl;
    }
    return 0;
}

标签:int,查集,合并,集合,vec,启发式,find
From: https://www.cnblogs.com/Sun-Wind/p/16795739.html

相关文章

  • 森林与并查集
    相关算法合并的时间复杂度查找的时间复杂度Quick-Find算法O(N)O(1)Quick-Union算法O(lgN)~O(N)O(lgN)~O(N)Weighted按质优化O(lgN)O(lgN)路径压......
  • 【Pandas总结】第七节 Pandas 合并数据集_pd.concat()
    将不同的数据源合并在一起是数据处理中最有趣的事情之一,在pandas中进行数据的合并,既可以使用pd.concat进行简单的数据合并,也可以使用pd.merge,pd.join进行复杂的合并;本节......
  • UE4学习笔记5——画刷;合并BSP;合并Actor
    P15.BSP画刷的概述和使用方法P16.房子搭建全流程P17.静态网格模型碰撞设置P18.合并Actor(合并静态网格体)P15画刷在哪?放置actor->几何体,这些就是所谓的画刷......
  • css外边距折叠和外边距合并
    【外边距折叠】两个嵌套关系的(父子关系)块元素,当父元素有上外边距或者没有上外边距(margin-top),子元素也有上外边距的时候。两个上外边距会合成一个上外边距,以值相对较大的上......
  • 617. 合并二叉树
    /***Definitionforabinarytreenode.*structTreeNode{*intval;*TreeNode*left;*TreeNode*right;*TreeNode():val(0),left(......
  • Codeforces Round #747 (Div. 2) D // 扩展域并查集
    题目来源:CodeforcesRound#747(Div.2)D-TheNumberofImposters题目链接:Problem-D-Codeforces题意有\(n\)个人,每个人拥有\(imposter\)或\(crewmate\)的身份......
  • 利用Power Pivot完成数据的“分类合并”问题!
    Excel情报局职场联盟Excel生产挖掘分享Excel基础技能Excel爱好者大本营用1%的Excel基础搞定99%的职场问题做一个超级实用的Excel公众号Excel是门手艺玩转需要勇气数万Excel......
  • 逆向查找合并单元格中的数据,经典用法!
    Excel情报局职场联盟Excel生产挖掘分享Excel基础技能Excel爱好者大本营用1%的Excel基础搞定99%的职场问题做一个超级实用的Excel公众号Excel是门手艺玩转需要勇气数万Excel......
  • 如何统计Excel中合并单元格的数量?
    Excel情报局职场联盟Excel生产挖掘分享Excel基础技能Excel爱好者大本营用1%的Excel基础搞定99%的职场问题做一个超级实用的Excel公众号Excel是门手艺玩转需要勇气数万Excel......
  • 多个单元格合并单元格,如何使原数据不丢失?
    Excel情报局职场联盟Excel生产挖掘分享Excel基础技能Excel爱好者大本营用1%的Excel基础搞定99%的职场问题做一个超级实用的Excel公众号Excel是门手艺玩转需要勇气数万Excel......