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

hdu 2818 Building Block(加权并查集)2009 Multi-University Training Contest 1

2015-08-22 17:30 549 查看
题意:

一共有30000个箱子,刚开始时都是分开放置的。接下来会有两种操作:

1. M x y,表示把x箱子所在的一摞放到y箱子那一摞上。

2. C y,表示询问y下方有多少个箱子。

输入:

首行输入一个整数m,表示一共有m次操作。

接下来每次操作都是上面所说的两种中的一种。

输出:

每次C y,输出一个结果,每次输出占1行。

就是不知道究竟是只有一组测试样例还是有多组测试样例,不过我还是按照多组的方式写了。

题解:

这道题我自己思考了好久都没有思路,最后中忍不住去看了题解,然后被题解震惊了。

明明只有1个权值,题解中的方式愣是把这一个权拆成了两部分,然后算出结果,Orz。

两个权是tot[], sum[],tot[i]表示i所在的箱子堆中一共有tot[i]个箱子,其中只有根节点的tot[i]是必须的。sum[i]则表示i下方共有sum[i]个箱子。

接下来,每次合并时,都将被合并的根节点fx的sum[]值加上仍然存在的根节点fy的tot[]值,然后fy的tot[]则加上fx的tot[]。

即,sum[fx] += tot[fy]; tot[fy] += tot[fx];

接下来,每次查找时,都要讲节点x的sum[]加上x的父节点的sum[]。

即,sum[x] += sum[fm[x]];

具体见代码——

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

const int N = 30010;

int fm
, sum
, tot
;
int n;
int a, b;
char s[2];

void init()
{
for(int i = 0; i < N; i++)          //很坑爹,题目明明说是1~30000,但是必须将0也初始化才能过
{
fm[i] = i;
sum[i] = 0;
tot[i] = 1;
}
}

int mfind(int x)
{
if(x == fm[x]) return x;
int t = fm[x];
fm[x] = mfind(fm[x]);
sum[x] += sum[t];
return fm[x];
}

void mmerge()
{
int fx = mfind(a);
int fy = mfind(b);
if(fx != fy)
{
fm[fx] = fy;
sum[fx] += tot[fy];
tot[fy] += tot[fx];
}
}

void work()
{
for(int tm = 1; tm <= n; tm++)
{
scanf("%s", s);
if(s[0] == 'M')
{
scanf("%d%d", &a, &b);
mmerge();
}
else
{
scanf("%d", &a);
mfind(a);
printf("%d\n", sum[a]);
}
}
}

int main()
{
//freopen("test.in", "r", stdin);
while(~scanf("%d", &n))
{
init();
work();
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: