带权并查集-Building Block
題目:
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; }總結
以上是生活随笔為你收集整理的带权并查集-Building Block的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: floquet端口必须沿z轴设置_Ans
- 下一篇: 华为防火墙查看日志命令_华为防火墙异常日