Cube Stacking
Time Limit: 2000MS Memory Limit: 30000K
Description
Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes labeled 1 through N. They start with N stacks, each containing a single cube. Farmer John asks Betsy to perform P (1<= P <= 100,000) operation. There are two types of operations:
moves and counts.
* In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y.
* In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value.
Write a program that can verify the results of the game.
Input
* Line 1: A single integer, P
* Lines 2..P+1: Each of these lines describes a legal operation. Line 2 describes the first operation, etc. Each line begins with a 'M' for a move operation or a 'C' for a count operation. For move operations, the line also contains two integers: X and Y.For count operations, the line also contains a single integer: X.
Note that the value for N does not appear in the input file. No move operation will request a move a stack onto itself.
Output
Print the output from each of the count operations in the same order as the input file.
Sample Input
6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4
Sample Output
1
0
2
一定要对并查集的路径查找以及压缩有一个清晰的理解,并且注意父节点不一定就是根节点。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int fa[31000], r[31000], dis[31000];//r就是当前节点到他父节点的距离(不一定是根节点)dis是当前节点以上有多少节点数,
//特别地对于根节点来说就是该集合中的所有点的数量。
int find(int x)
{
int y;
if(fa[x]!=x)
{
y=fa[x];
fa[x]=find(fa[x]);
r[x]+=r[y];//这个地方应该是最难理解的了,
//要求出x到根节点的距离应该等于 x->父节点 + 父节点->父节点的父节点 + .....+根节点。
//当递归到最深层次的时候,由于x原来的旧根节点已经指向了新的根节点,所以x这条路径上的所有祖先节点都可以得到优化
//再回溯到每一层x时,其父节点的父节点一定指向根节点。
//此时r[x]自然等于x->父节点+父节点->根节点即可。
}
return fa[x];
}
void join(int x, int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
fa[fx]=fy;
r[fx]+=dis[fy];//这也好理解,fx本来是根节点,但是指向fy之后,那么fx到fy的距离就是fy那个集合中所有的点的数量
//毕竟并入的过程模拟堆栈只能从后面加入。
dis[fy]+=dis[fx];//很好理解fy是根节点,现在其他的集合并过来,那么以fy为根节点的集合中节点数就应该加上新的集合的数量
}
}
int main()
{
int n, a, b, i, f1, f2;
char c;
scanf("%d",&n);
for(i=1;i<=30000;i++)
{
fa[i]=i;
r[i]=0;
dis[i]=1;
}
while(n--)
{
getchar();
scanf("%c",&c);
if(c=='M')
{
scanf("%d%d",&a,&b);
join(a,b);
}
else
{
scanf("%d",&a);//注意r[a]仅仅代表a->父节点的距离,这里查询的a节点不一定已经完成了路径压缩。
find(a);//所以对a节点进行路径压缩。
printf("%d\n",r[a]);
}
}
return 0;
}