【POJ1988】Cube Stacking(并查集水题)

题面:【POJ1988】Cube Stacking

题意:

有n个编号分别为1~n的立方体以及两种操作,一种是move操作,一种是count操作。move操作就是让你把含x的一堆立方体移到含y的一堆立方体的上面,count操作就是让你求出编号为x的立方体底下有几个立方体。

解析:

一看到这道题,很容易就能想到用并查集来做,而这道题也的确是用并查集来做的O(∩_∩)O~

首先,我们先来考虑move操作。当你要把两堆立方体堆在一起时,可以把底下那堆的堆顶的father更新为上面那堆的堆顶,这应该是很容易想到的。

那么,应该如何求出编号为x的立方体底下的方块数呢?

我们可以用Under[x]来记录编号为x的立方体底下有多少个方块,这样,输出时只要输出Under[x]即可。

可是我们不可能持续更新Under[x],这样的复杂度太大了,因此,我们可以用一个Up[]数组来记录每个立方体到它所在的那堆立方体的堆顶的距离,这样只要持续更新每一堆的堆顶的Under[]值即可。

而这一步只需在合并时就能顺便完成了,几乎无需任何复杂度。

并且,Up[]数组的更新也是非常容易的,只需在并查集函数getfa()中加一句Up[x]+=Up[f[x]]即可。

这样一来,就可以发现Under[x]=Under[getfa(x)]-Up[x],因此输出时只要输出Under[getfa(x)]-Up[x]就可以了。

代码如下:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#define max(x,y) (x>y?x:y)
#define min(x,y) (x<y?x:y)
#define N 30000
#define M 100000
using namespace std;
int m,f[N+5],Up[N+5],Under[N+5];
int read()
{
	int x=0,f=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	while(ch>='0'&&ch<='9') (x*=10)+=ch-'0',ch=getchar();
	return x*=f;
}
void write(int x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
int getfa(int x)//并查集函数
{
	if(f[x]==x) return x;
	int fx=getfa(f[x]);
	Up[x]+=Up[f[x]],f[x]=fx;//更新f[]和Up[]两个数组
	return f[x];
}
int main()
{
	for(int i=1;i<=N;i++) f[i]=i,Up[i]=Under[i]=0;//初始化
	m=read();
	for(int i=1;i<=m;i++) 
	{
		char ch;
		cin>>ch;
		if(ch=='M')
		{
			int x=read(),y=read(),fx=getfa(x),fy=getfa(y);
			Up[fy]=Under[fx]+1,(Under[fx]+=Under[fy])++,f[fy]=fx;//更新上面一堆堆顶的Under[]值以及下面一堆堆顶的father
		}
		if(ch=='C')
		{
			int x=read(),fx=getfa(x);
			write(Under[fx]-Up[x]),putchar('\n');//输出
		}
	}
	return 0;
}




版权声明:转载请注明地址

猜你喜欢

转载自blog.csdn.net/chenxiaoran666/article/details/80213343