题目传送门: -------->这里<----------
题目大意:
有标记1-N的方块,初始时一个砖块是一堆。然后进行以下操作
M X Y : 将 X 砖块所在堆 叠到 Y 砖块所在堆上面;
C X :数在 X 砖块所在堆中 叠在X砖块下的砖块个数;
1<=N<=30000;
思路:
并查集,每一个砖块堆是一个集合。将每一堆的最上面一块砖设为根,合并时更新 Y 堆的根的 father 和 val (在Y上面的方块数) 。 要达到这些目的,需要一个all数组,来记录每一堆里的砖块总数,和一个val数组,来记录具体某一块砖上面的砖块个数。输出时,输出all - val - 1;在find函数中进行路径压缩的,记住回溯时将val值相加。
初始时 all 数组 全为 1 ,不能用memset初始化int 数组全为1,因为memset是按字节填充,会使值错误。
val 数组 全为 0。
father[x] = [x];
代码:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX 30010 5 6 using namespace std; 7 int val[MAX]; 8 int all[MAX]; 9 int father[MAX]; 10 void init() 11 { 12 memset(val,0,MAX * sizeof(int)); 13 for(int i = 0 ; i < MAX ; i++) 14 { 15 father[i] = i; 16 all[i] = 1; 17 } 18 return ; 19 } 20 int Find_Root(int x) 21 { 22 if(father[x] == x) 23 { 24 return x; 25 } 26 int temp = father[x]; 27 father[x] = Find_Root(father[x]); 28 val[x] += val[temp]; 29 return father[x]; 30 } 31 32 33 void M (int a ,int b) 34 { 35 if(a == b) return ; 36 father[a] = b; 37 val[a] += all[b]; 38 all[b] += all[a]; 39 return ; 40 } 41 42 void C(int a) 43 { 44 cout << all[Find_Root(a)] - val[a] - 1 << endl; 45 return ; 46 } 47 48 49 int main() 50 { 51 int T; 52 while(~scanf("%d",&T)) 53 { 54 init(); 55 for (int i = 0; i < T; ++i) 56 { 57 char op; 58 int n,m; 59 cin >> op ; 60 if(op == ‘M‘) 61 { 62 cin >> n >> m; 63 M(Find_Root(m),Find_Root(n)); 64 } 65 else if(op == ‘C‘) 66 { 67 cin >> n; 68 C(n); 69 } 70 ////////////////////////////// 71 } 72 } 73 return 0; 74 75 }
时间: 2024-12-14 06:35:38