题目:
John are playing with blocks. There are N blocks (1 <= N <= 30000) numbered 1…N。Initially, there are N piles, and each pile contains one block. Then John do some operations P times (1 <= P <= 1000000). There are two kinds of operation:
M X Y : Put the whole pile containing block X up to the pile containing Y. If X and Y are in the same pile, just ignore this command. 
 C X : Count the number of blocks under block X 
You are request to find out the output for each C operation. 
 Input 
 The first line contains integer P. Then P lines follow, each of which contain an operation describe above. 
 Output 
 Output the count for each C operations in one line. 
 Sample Input 
 6 
 M 1 6 
 C 1 
 M 2 4 
 M 2 6 
 C 3 
 C 4 
 Sample Output 
 1 
 0 
 2
分析与解答:
题意: 
  
 N:有1到N个数 
 M x y :把x所在的堆放到y所在的堆上面 
 C x:输出x下面有几个数
这个博客说钢管串砖块启发了我。。 
 https://blog.csdn.net/viphong/article/details/51934799 
 我觉得这一点不美观,我更喜欢用竹签串鱼蛋描述
我们直接看复杂的过程,就是这两串鱼蛋我们把他撸到一串的过程。。 
 
如果把第二串撸到第一串上的话,正常的话我们肯定是把第二串的两个鱼蛋拔出来,然后按到第一串上,也就是下面这个样子。。
现在题目问我某个鱼蛋底下有几个鱼蛋
假设所有竹签一开始只有一个鱼蛋
我们先看看怎么移动
移动的话我们先找两个串最底下的那个鱼蛋 
 假设d[x]是指鱼蛋x下边有几个鱼蛋 
 r[x]是指鱼蛋x所在的串上一共有几个鱼蛋,这里我们让最底下的鱼蛋存他那一串鱼蛋的总数
注意我们转移的时候是连根拔起,必须找到最底下的鱼蛋,再移动(因为一个集合的缘故) 
 我们找到分别是两串鱼蛋最底下的那个鱼蛋fx,fy 
 就可以更新d[fx],d[fx]=r[fy] 
 然后我们更新r[fy],现在r[fy]=r[fx]+r[fy](注意观察图像)
那当然了,他不可能只问最底下的鱼蛋,他可能问串中间的,此时我们就通过find函数改中间的鱼蛋下面的鱼蛋数d[x]
比如新的d[2]=老的d[2]+新的d[4]=1+r[fy]=1+2=3
find用的递归,也就是说会先找到最底下的鱼蛋,然后依次返回就把最底下的上一个鱼蛋的d[]给更新了
所以为什么我们输出d[x]前先调用一下find,目的就是为了更新
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAX 30000+5
using namespace std;
int pre[MAX];
int d[MAX];
int r[MAX];
int init(){ for(int i=0; i<=MAX; i++){pre[i]=i;d[i]=0;r[i]=1;}
}
int Find(int x){int fx;if(x==pre[x]) return x;fx=pre[x];pre[x]=Find(fx);d[x]=d[x]+d[fx];//return pre[x];
}
void Union(int x, int y){int fx=Find(x), fy=Find(y);if(fx==fy) return;pre[fx]=fy;     d[fx]=r[fy];//r[fy]+=r[fx]; //return;
}
int main(){int P;scanf("%d",&P);init();while(P--){char op[5];int x, y;scanf("%s",op);if(op[0]=='M'){scanf("%d%d",&x,&y);Union(x,y);}else{scanf("%d",&x);Find(x);printf("%d\n",d[x]);}}return 0;
}