POJ 1988 Cube Stacking( 带权并查集 )*

本文解析了POJ1988 CubeStacking题目,通过使用带权并查集解决移动集合和计算元素数量的问题。介绍了核心算法思想,并提供了实现代码。

POJ 1988 Cube Stacking( 带权并查集 )


非常棒的一道题!借鉴“找回失去的”博客

链接:传送门

题意:

  • P次查询,每次查询有两种:
    1. M x y 将包含x的集合移动到y上面
    2. C x, 计算x下面有几个元素。用p[x]表示x的根结点,

思路:cnt[x] 表示x所在集合的元素个数,top[x] 表示x上面有几个元素。每次进行路径压缩时,top[x] 都要加上 top[ par[x] ],cnt 和 par 的操作就是并查集的基本操作。最后计算结果是用 x 所在集合元素的个数 - 在它之上的个数 - 它本身

balabala:这次修改在寻找 x 根节点和合并时更新两个维护数组非常棒,涨姿势了!


/*************************************************************************
    > File Name: poj1988.cpp
    > Author:    WArobot 
    > Blog:      http://www.cnblogs.com/WArobot/ 
    > Created Time: 2017年05月08日 星期一 22时27分30秒
 ************************************************************************/

#include<iostream>
#include<cstdio>
using namespace std;

const int maxn = 100000+10;
int n , par[maxn] , cnt[maxn] , top[maxn];  
// cnt[x]表示x集合的元素个数 
// top[x]表示x上面有几个元素每次路径压缩top[x]都要加上top[par[x]]
// 答案就是x所在集合的元素个数-在它之上的个数-本身
int find(int x){ 
    if( par[x] == x )   return x;
    else{
        int t = par[x];     // px记录一下现在x点父亲是谁
        par[x] = find(par[x]); 
        top[x] += top[t];   // 修正x的高度
        return par[x];
    }
}
void unite(int x,int y){
    int fx = find(x) , fy = find(y);
    if(fx!=fy){
        par[fy] = fx;
        top[fy] = cnt[fx];  // 将x集合放在y集合之上
        cnt[fx] += cnt[fy];
    }
}
int main(){
    int x,y;
    char op;
    while(~scanf("%d",&n)){
        for(int i=0;i<maxn;i++){
            par[i] = i , cnt[i] = 1 , top[i] = 0;
        }
        for(int i=0;i<n;i++){
            cin >> op >> x;
            if(op=='M'){
                scanf("%d",&y);
                unite(x,y);
            }
            else{
                int ans , nx;
                nx = find(x);
                ans = cnt[nx] - top[x] - 1;
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/WArobot/p/6828679.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值