并查集 带权并查集 反集

并查集

并查集最基本的操作——合并、查询

struct{
    int p,r;//p:parent r:rank(秩,子树高度的下界)
}n[MAX];
void init(){//初始化并查集:每个元素都是自身的根节点,秩为0
    for(int i=1;i<=MAX;i++)
        n[i].p=i,n[i].r=0;
}
  • 查:查找x所属的子树(路径压缩:将每个节点的父节点更新为其祖先)
int find(int x){
    if(x!=a[x].parent)//x不是根节点,继续向上找,直至找到祖先(祖先的父节点为其自己)
        a[x].parent=find(a[x].parent);
    return a[x].parent;
}
  • 并:合并x和y节点(按秩合并/启发式合并,秩小的合并到秩大的上)
void merge(int x,int y){
    int rx=find(x),ry=find(y);
    if(rx!=ry){//x和y不属于相同树上的节点,进行合并
        if(a[rx].rank>a[ry].rank)
            a[ry].parent=rx;
        else{
            a[rx].parent=ry;
            if(a[rx].rank==a[ry].rank) a[ry].rank++;//秩相等则合并后秩+1
        }
    }
}

带权并查集

节点与其父节点间存在权值,以权值相加为例

struct{
    int p,r,w;//w:记录节点与其父节点间的权值
}n[MAX];
void init(){//需将权值也初始化为0
    for(int i=1;i<=MAX;i++)
        n[i].p=i,n[i].r=0,n[i].w=0;
}
  • 查:节点权值与其原父节点权值层层相加,通过递归实现权值相加到新父节点
int find(int x){
    if(n[x].p!=x){
        int t=n[x].p;//保存原父节点
        n[x].p=find(node[x].p);
        n[x].w+=n[t].w;//经过递归原父节点权值已经改变,节点权值加上原父节点权值就行了
    }
    return n[x].p;
}
  • 并:具体问题具体分析
void merge(int x,int y,int w) {//w:x和y间的权值差异
    int rx=find(x),ry=find(y);
    if(rx!=ry){
        if(node[rx].r<node[ry].r){
            node[rx].p=ry;
            node[rx].w=w+node[y].w-node[x].w;
        }else{
           node[ry].r=rx;
           node[ry].w=-w+node[x].w-node[y].w;
           if(node[rx].r==node[ry].r) node[rx].r++;
        }
    }
}

种类并查集(反集)

集合中同时记录2种性质的信息:朋友和敌人。

实现:开2倍长的数组(2*n), 1 − n 1-n 1n表示元素 1 − n 1-n 1n一一对应的朋友节点集合的根节点,但朋友集合元素间不一定为朋友; n − 2 n n-2n n2n​​为元素 1 − n 1-n 1n一一对应的敌人集合的根节点,但敌人集合元素间不一定为敌人。

例:对于元素a:a:指其朋友集合中的根节点,即为自己;a+n:指其所对应的敌人集合的根节点(如:n=4,则1和5为敌对关系,以此类推)

合并:每次进行合并操作的都是朋友关系。如a和b如果是朋友,则merge(a,b)。

为维护敌对关系,如a和b是敌人,则将b的敌人与a合并(merge(b+n,a)),a的敌人与b合并(merge(a+n,b)),合并结果为b的敌人与a成为朋友(即a成为b的敌人),a的敌人与b成为朋友(即b成为了a的敌人)。

注意:元素 n − 2 n n-2n n2n所构成的敌人集合,只是为了维护敌对关系而虚构出来的集合,实际上并不另外存在n个敌人。因此维护敌对关系时,并不能直接操作敌人集合,而是必须通过操作朋友集合来间接操作敌人集合。(即进行合并时**一定要注意合并顺序!**只能向朋友集合上合并,不可以向敌对集合上合并!必须将a+n的父节点设为b,b+n的父节点设为a!)

posted @   椰萝Yerosius  阅读(5)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示