pku1988(Cube Stacking)

今天效率还不错,再接再厉^-^

总得来说,这道题目不难,但悲剧的是,我一开始理解错题意了

题意:1)n个队列,n个立方体。

        2)初始化时候每个队列有一个立方体。

        3)两个操作:m x y:将x所在的集合放到y所在的集合里面,说白了,就是将y所在集合放到x所在集合后面

                           c x:问x立方体下面有多少个立方体

呵呵,发现,其实,每次“真正”执行find()的时候,实际上都是对Union的进一步维护,只有进行一次与节点x有关的Union时,才会对x维护,而且,维护过后,x节点之上的节点也会同时被维护,并且直接挂到根节点上,这意味着之后对另一些点的维护并不会影响到已维护了的节点

还有就是那个计算,节点x之下的元素个数=x所在集合的元素个数-x之上的元素-1,很好理解吧

更具体的解释,见代码:

#include<stdio.h>
#define MAXN 30010
int f[MAXN],r[MAXN],above[MAXN];
//f[]记录父节点,r[a]记录元素a所在集合的元素个数,above[a]记录a之上 的元素个数
void init()//初始化
{
	int i;
	for(i=1;i<=MAXN;i++)
	{
		f[i]=i;
		r[i]=1;
		above[i]=0;
	}
}
int find(int x)
{
	if(x==f[x])
		return f[x];
	int t=find(f[x]);
	above[x]+=above[f[x]];
	f[x]=t;
	return f[x];
}//查找根节点,路径压缩,同时维护above[]的值,同样,还是留意一下递归过程,你会发现一个很重要的东西
//类似于回溯,到根节点之后,回溯的时候,每一个元素都直接挂到根节点上了
//这样也就避免了重复操作,呵呵,其实这也是路径压缩的关键所在
void Union(int x,int y)
{
	int a=find(x);
	int b=find(y);
	if(a==b)
		return ;
	above[b]=r[a];
	r[a]+=r[b];
	f[b]=a;
}//将y所在集合挂到x所在集合,虽说是挂在元素x所在集合的后面,实际上是直接挂在根节点上
//这也引出了一个词,"逻辑上的距离",above记录节点到根节点逻辑上的距离
int main()
{
	int i,a,b,n;
	char ch[2];
	scanf("%d",&n);
    	init();
	  for(i=1;i<=n;i++)
	   {
		scanf("%s",ch);
		if(ch[0]=='M')
		{
			scanf("%d %d",&a,&b);
			Union(a,b);
		}
		else 
		{
			scanf("%d",&a);
			printf("%d\n",r[find(a)]-above[a]-1);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/nanke/p/2040562.html