您的位置:首页 > 产品设计 > UI/UE

HDU 2818 Building Block (带权并查集)

2017-05-15 21:03 274 查看
参考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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: