• UVA 11987 Almost Union-Find (并查集)


    题意:

    这里有N个数编号1 ~N,开始每个数各自在一个集合里面,然后有三种命令:

    1 P Q  :把 P 所在的集合和 Q 所在的集合合并,如果已经在一个集合里面了就忽视

    2 P Q : 把 P 这个元素从它所在的集合里面拿出来放到 Q 里面,,如果已经在一个集合里面了就忽视

    3 P :询问 P 所在集合元素的 个数 和P所在集合元素的 和。

    思路:

      对于命令 1 直接合并就好了,用cnt[]数组代表元素个数,sum[]数组代表元素的和,合并的同时维护数组即可,对于命令 2 ,需要好好想一想,如果 P  不是根节点还好,如果是根节点的话,直接合并难免会出问题,所以可以重新开一个数组,d[],用来代表节点的编号,刚开始 d[i]存的都是i;当命令2 时 我们可以在题目所给的节点之外重新找个节点(1 ~N之外),比如 N +1.让 d[P] = N +1;(第二次就是N+2,总之就是重新找个不存在的节点来覆盖当前这个节点。)这样原来集合里面的那个 P  就失效了,我们合并 d[P] 和 d[Q]就好了,因为原来集合里面的 d[P] 节点已经不叫 P了,而是叫 N+1了,这样我们就不用考虑是否是根节点了。命令3直接查询就好了~~~具体看代码、、、、、

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cstdlib>
     5 #include <cmath>
     6 #include <cctype>
     7 #include <algorithm>
     8 using namespace std;
     9 const int MAXN =1e5 + 3;
    10 int pre[MAXN*2],cnt[MAXN*2],sum[MAXN*2],d[MAXN*2];//依次为父节点数组,个数数组,求和数组,代号数组
    11 
    12 int Find(int x)
    13 {
    14     int r = x;
    15     while(pre[r] != r)
    16     {
    17         r = pre[r];
    18     }
    19     int i = x,j;
    20     while(pre[i] != r)
    21     {
    22         j = i;
    23         i = pre[i];
    24         pre[j] = r;
    25     }
    26     return r;
    27 }
    28 void Mix(int a,int b)
    29 {
    30      int fa = Find(a),fb = Find(b);
    31      if(fa != fb)
    32      {
    33         pre[fa] = fb;
    34         sum[fb] += sum[fa];       //合并的同时维护两个数组
    35         cnt[fb] += cnt[fa];
    36      }
    37 }
    38 void make_set(int n)     //初始化初始化初始化
    39 {
    40     for(int i = 1; i <= n; i++){
    41         pre[i] = i;
    42         sum[i] = i;
    43         cnt[i] = 1;
    44         d[i] = i;
    45     }
    46 }
    47 
    48 int main()
    49 {
    50    //freopen("in.cpp","r",stdin);
    51     void debug(int n);
    52     int n,m;
    53     while(~scanf("%d%d",&n,&m))
    54     {
    55         make_set(n);
    56         int temp = n + 1;
    57         while(m--)
    58         {
    59             int order;
    60             scanf("%d",&order);
    61             if(order == 1)       //命令一  直接合并就好了
    62             {
    63                 int p,q;
    64                 scanf("%d%d",&p,&q);
    65                 Mix(d[p],d[q]);
    66               // debug(n);
    67             }
    68             else if(order == 2)              //命令二
    69             {
    70                 int p,q;
    71                 scanf("%d%d",&p,&q);
    72                 int fp = Find(d[p]),fq = Find(d[q]);  
    73                  if(fp != fq) {
    74                     sum[fp] -= p;               //更新原来的集合数组
    75                     cnt[fp] --;
    76                     d[p] = temp++;         //新来了一个点代号 temp ,并覆盖原来的那个点,原来d[p] = p 现在等于 trmp 了
    77                     sum[d[p]] = p;       //新来这个点的 sum 数组初始化
    78                     cnt[d[p] ]= 1;     //cnt 数组初始化
    79                     pre[d[p]] = d[p];    //pre 数组初始化
    80                 }
    81                 Mix(d[p],d[q]);     //直接合并就好了
    82                    //  debug(n);
    83             }
    84             else if(order == 3)
    85             {
    86                 int p;
    87                 scanf("%d",&p);
    88                int fp = Find(d[p]);
    89                 printf("%d %d
    ",cnt[fp],sum[fp]);
    90             }
    91         }
    92     }
    93     return 0;
    94 }
  • 相关阅读:
    mysql03聚合函数
    栈、队列、循环队列、双端队列、优先级队列04
    OOAD之策略模式(1)
    jvm01:java内存区域与内存
    Python+Selenium
    Python+Selenium
    Python+Selenium
    Python+Selenium
    Python+Selenium
    Python+Selenium
  • 原文地址:https://www.cnblogs.com/Ash-ly/p/5397648.html
Copyright © 2020-2023  润新知