洛谷P2342-疊積木
阿新 • • 發佈:2018-08-19
換行 output == temp out 問題 分開 n) 數組
Problem 洛谷P2342-疊積木
Accept: 373 Submit: 1.1k
Time Limit: 1000 mSec Memory Limit : 128MB
Problem Description
約翰和貝西在疊積木。共有30000塊積木,編號為1到30000。一開始,這些積木放在地上,自然地分成N堆。貝西接受約翰的指示,把一些積木疊在另一些積木的上面。一旦兩塊積木相疊, 彼此就再也不會分開了,所以最後疊在一起的積木會越來越高。約翰讓貝西依次執行P條操作,操作分為兩種:
- 第一種是移動操作,格式為“移動X到Y的上面”。X和Y代表兩塊積木的編號,意思是將X所的那堆積木,整體疊放到Y所在的那堆積木之上;
- 第二種是統計操作,格式為“統計Z下方的積木數量”。Z代表一塊積木的編號,意思是貝西需要報告在編號為Z的積木之下還有多少塊積木;
請編寫一個程序,幫助貝西回答每條統計問題。
Input
第一行:單個整數:P,1 ≤ P ≤ 10^5
第二行到第P + 1行:每行描述一條命令,如果這行開頭的字母是 M,代表一條移動命令,後面的兩個整數代表上文中的X和Y;如果開頭字母是 C,代表一條統計命令。後面的整數代表上文中的Z,保證所有的移動命令都有意義,X和Y不會已經出現在同一堆積木裏
Output
對每一個統計命令,輸出正確回答,用換行符分開每個查詢的結果
Sample Input
6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4
Sample output
1
0
2
題目鏈接:https://www.luogu.org/problemnew/show/P2342
題解:感覺這個題和一般的帶權並查集有那麽一點點區別,記錄下來。
每個集合的父節點是一堆積木的最下面的積木,權值是當前積木到所在集合父節點的積木個數。
兩點需要註意的,一是集合內部關系更改,也就是rel數組,這個是在路徑壓縮的過程中遞歸實現的,二是集合之間關系的更改,不僅需要rel數組,還要利用Size數組(記錄每個集合當前的大小),當把一個集合放在另一個集合上面時,上面積木的底部到下面積木的底部的積木個數就是Size[下面積木]。
別忘了當一堆積木放在別的積木上面的時候,Size要修改為0。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 using namespace std; 6 7 const int maxn = 30000+10; 8 9 int rel[maxn],pre[maxn]; 10 int Size[maxn]; 11 12 int findn(int x){ 13 if(x == pre[x]) return x; 14 int temp = pre[x]; 15 pre[x] = findn(pre[x]); 16 rel[x] += (rel[temp]); 17 return pre[x]; 18 } 19 20 void merge_node(int x,int y){ 21 int fx = findn(x); 22 int fy = findn(y); 23 if(fx != fy){ 24 pre[fx] = fy; 25 rel[fx] = Size[fy]; 26 Size[fy] += Size[fx]; 27 Size[fx] = 0; 28 } 29 } 30 31 int main() 32 { 33 //freopen("input.txt","r",stdin); 34 int p,n,x,y; 35 char ch[10]; 36 n = 30005; 37 for(int i = 0;i < n;i++){ 38 pre[i] = i; 39 rel[i] = 0; 40 Size[i] = 1; 41 } 42 scanf("%d",&p); 43 for(int i = 1;i <= p;i++){ 44 scanf("%s",ch); 45 if(ch[0] == ‘M‘){ 46 scanf("%d%d",&x,&y); 47 merge_node(x,y); 48 } 49 else{ 50 scanf("%d",&x); 51 findn(x); 52 printf("%d\n",rel[x]); 53 } 54 } 55 return 0; 56 }
洛谷P2342-疊積木