并查集 POJ 1988 Cube Stacking

题目传送门:     -------->这里<----------

题目大意:

  有标记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 }
原文地址:https://www.cnblogs.com/ticsmtc/p/4976208.html