zoukankan      html  css  js  c++  java
  • HDU 3635 Dragon Balls(带权并查集)

    题目链接

    题目大意

      有标号为1到n的n个龙珠,分别放在对应标号为1到n的n个城市里。
      下面有两种操作:

    • T A B表示把A龙珠所在城市的所有龙珠都转移到B龙珠所在的城市中
    • A 表示查询A,需要知道A龙珠现在所在的城市,A所在的城市有几颗龙珠,A转移到这个城市移动了多少次,分别输出3个整数,表示上述信息。

    解题思路

      本题可以通过带权并查集来解决。可以发现,将集合a的父节点挂到集合b的父节点上,则属于集合a的节点的移动次数都要+1,而属于集合b的节点的移动次数无需改变,合并后的集合的节点数量等于两个集合的节点数量之和。对于查询操作,第一个相当于是询问父节点;第二个问集合元素个数,只要在合并的时候让两个集合数量相加即可;
      重点就是第三个,如何计算移动次数了。可以把需要移动的集合的父节点挂到目标集合的父节点上,然后更新合并后的子节点的值,令需要移动的集合的子节点都加上1。这个可以在路径压缩的过程中,把需要移动的集合的父节点处的sum值置成1,而目标集合的父节点置成0来实现。

    代码

    const int maxn = 1e4+10;
    int p[maxn], num[maxn], sum[maxn];
    int find(int x) {
        if (p[x]!=x) {
            int tmp = p[x];
            p[x] = find(p[x]);
            sum[x] += sum[tmp];
        }
        return p[x];
    }
    int main(void) {
        int t, kase = 1; scanf("%d",&t);
        while(t--) {
            int n,q; scanf("%d%d",&n,&q);
            printf("Case %d:
    ",kase++);
            for (int i = 0; i<=n; ++i) {
                p[i] = i; num[i] = 1; sum[i] = 0;
            }
            char ch[3]; int a, b;
            while(q--) {
                scanf("%s",ch);
                if(ch[0]=='T') {
                    scanf("%d%d",&a,&b);
                    int fa = find(a), fb = find(b);
                    if (fa!=fb) {
                        p[fa] = fb;
                        sum[fa] = 1;
                        num[fb] += num[fa];
                    }
                }
                else {
                    scanf("%d",&b); find(b);
                    printf("%d %d %d
    ",find(b),num[find(b)],sum[b]);
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    19. vue的原理
    18.jwt加密
    17.vue移动端项目二
    16.vue-cli跨域,swiper,移动端项目
    15.vue动画& vuex
    14.vue路由&脚手架
    13.vue组件
    12.vue属性.监听.组件
    11.vue 数据交互
    从尾到头打印链表
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/13042783.html
Copyright © 2011-2022 走看看