题目:
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;
}