HDU 2818 Building Block (带权并查集)

参考http://blog.163.com/i_am_an_alp/blog/static/2403891682014921102227653/

这个题感觉很有意思!!!!!!!!
还是花了些时间的
题意:给你p种操作,操作分别有
1 x y 表示将带有x的一堆放到y的上面
2 x 表示询问x的下面有多少个blocks
对于每次的询问,我们都要输出相应的答案

分析:我们怎么知道一个数下面有多少个数呢?把一堆放到另一堆上,我们只能知道上一堆的最下面一个的答案是下面那一堆的节点数,那上面的那一堆其他的答案怎么求呢,相当于他们原来本身的加上 下面一堆的。
所以我们开了三个数组
f:表示跟的关系
r[i]:表示以i为根的节点的个数
under[i]:表示i下面有多少个节点

然后这个题我感觉最有趣的地方是under数组的运用,我们之前都用过f和r数组,记录根的关系以及节点数。
但是这道题我们要求一个数下面有几个数,这个时候我们用并查集的时候要有一个顺序了,不然就不知道谁是最后一个了,所以我们要用最后一个节点作为根。然后怎么求i下面有多少个节点呢?我们每次将x堆放到y堆上面的时候,我们可以知道x底下(假设为z点)z点底下有多少个,就是y的节点数,然后z上面的点通过路径压缩也可以求得

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn = 30005;
int f[maxn],r[maxn],under[maxn];
//我们要合并x和y的时候,要找y的最底的和x的最底的
int findf(int k)//
{

  if(k==f[k]) return k;
  int t=f[k];
  f[k]=findf(f[k]);//这个不压缩的话,会导致MLE
  under[k]+=under[t];
  return f[k];
}

int main()
{
    int p;
    scanf("%d",&p);
    for(int i=0;i<maxn;i++)
    {
        f[i]=i;
        r[i]=1;
        under[i]=0;
    }
    for(int i=0;i<p;i++)
    {
        getchar();
        char c;
        scanf("%c",&c);
        int a,b;
        if(c=='M')
        {
            scanf("%d %d",&a,&b);
            int root1=findf(a);
            int root2=findf(b);
            if(root1!=root2)
            {
                under[root1]=r[root2];
                f[root1]=root2;
                r[root2]+=r[root1];
            }
        }
        else if(c=='C')
        {
            scanf("%d",&a);
            int root=findf(a);
            printf("%d\n",under[a]);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值