有N(N<=30,000)堆方块,开始每堆都是一个方块。方块编号1 – N. 有两种操作:
M x y : 表示把方块x所在的堆,拿起来叠放到y所在的堆上。
C x : 问方块x下面有多少个方块。
操作最多有 P (P<=100,000)次。对每次C操作,输出结果。
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
under[i]是指i的下面有多少方块,当两堆方块合并时,如,merge(a,b)将b堆根放在a堆根的下面,此时需要改变b堆的under值,他的值等于他的根的under值也就是a的under值加上他本身的under值。
在状态压缩过程中,也需要改变under的值,对于每一个结点,他们的under 值等于本身的under值加上他们的父节点的under的值
#include<iostream>
#include<cstdio>
#define n1 31000
using namespace std;
int pre[n1],under[n1];
int total[n1];
int n;
int p;
int getboot(int x){
if(x!=pre[x]){
int t=getboot(pre[x]);
under[x]+=under[pre[x]];
pre[x]=t;
return pre[x];
}
return x;
}
void Merge(int a,int b){
int pb=getboot(b);
int pa=getboot(a);
if(pb==pa)
return;
pre[pb]=pa;
under[pb]=total[pa];//堆方块时,pb连接到pa上,此时pb的下面全是a的方块,如图1
total[pa]+=total[pb];
}
int main(){
for(int i=0;i<n1;i++){
under[i]=0;
pre[i]=i;
total[i]=1;
}
scanf("%d",&p);
for(int i=0;i<p;i++)
{
char s[20];
int a,b;
scanf("%s",s);
if(s[0]=='M')
{
scanf("%d%d",&a,&b);
Merge(b,a);
}
else
{
scanf("%d",&a);
getboot(a);
printf("%d\n",under[a]);
}
}
return 0;
}