• HDU 3635 Dragon Balls(带权并查集)


    这题的关键是如何统计转移的次数

    根结点都是最多移动一次的,所以记录移动次数时把自己的加上父亲结点的就是移动总数了

    这里要注意:更新移动次数时,一定要先更新父亲的,在更新自己的,即用递归从最顶层开始往下更新

                     我的方法是在调用find_root前先更新一下,再路径压缩。

    网上看了有人写的,在查找父节点的时候同时更新的代码:

    int find_root(int x){
        int fa;
        if(father[x]==x)
            return x;
        fa=find(father[x]);
        int tmp=father[x];
        trans[x]+=trans[tmp];
        father[x]=fa;
        return fa;
    }
    /*
    trans表示的是从x转移到father[x]用的步数
    我们更新要变成x转移到根节点,这里也就是s用的步数
    就是要father[x]的trans更新完才能更新x的trans
    */


    下面附上我的代码:

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <vector>
    #include <set>
    
    using namespace std;
    int father[10010];
    int ranks[10010];  //表示以i为根节点的集合中所含有的个数
    int trans[10010];  //trans[i]表示i所移动的次数
    int n,q;
    
    void init(){
        for(int i=0;i<=n;i++){
            father[i]=i;
            ranks[i]=1;
        }
    }
    
    //x的父节点更新完相应的trans后,才能更新x的trans
    int update(int x){
        if(father[x]==x)
            return trans[x];
        else{
            trans[x]+=update(father[x]);
            return trans[x];
        }
    }
    int find_root(int x){
        /*一开始更新trans的方法写在这里,结果WA。
          后来发现:
          如果写在这里,在第一次find_root时就能更新完全,
          但是接下来还会调用find_root方法,父节点又会再更新一遍,等于多加了几次
          改了一下,每次在调用find_root方法前,调用update()方法,AC
    
        */
        //trans[x]+=update(father[x]);
        if(father[x]!=x){
            father[x]=find_root(father[x]);
        }
        return father[x];
    }
    
    void Union(int a,int b){
    
        trans[a]+=update(father[a]);
        trans[b]+=update(father[b]);
        int x=find_root(a);
        int y=find_root(b);
        if(x==y)
            return;
        //是trans[x]++,一开始写了trans[a]++。。。
        trans[x]++;
        father[x]=y;
        ranks[y]+=ranks[x];
    
    }
    
    int main()
    {
        int t,a,b,x,y,z;
        char ch[4];
        scanf("%d",&t);
        for(int i=1;i<=t;i++){
            memset(trans,0,sizeof(trans));
            printf("Case %d:
    ",i);
            scanf("%d%d",&n,&q);
            init();
            for(int i=1;i<=q;i++){
                scanf("%s",ch);
                if(ch[0]=='T'){
                    scanf("%d%d",&a,&b);
                    Union(a,b);
                }
                else{
                    scanf("%d",&a);
                    trans[a]+=update(father[a]);
                    x=find_root(a);
                    y=ranks[x];
                    z=trans[a];
                    printf("%d %d %d
    ",x,y,z);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    [记录]Eclipse版本选择和安装
    Nexus+Maven安装配置手册
    Eclipse编写Java程序
    Tomcat下载和配置
    SQL Server如何清除连接过的服务器名称历史?
    为文本添加全选Ctrl + A 功能
    配置Eclipse使用TFS源码管理
    [jQuery] jSrcollable
    [ios] cocos2d/cocos2dx 演示
    [c++] 实现类似printf这样的函数
  • 原文地址:https://www.cnblogs.com/chenxiwenruo/p/3289357.html
Copyright © 2020-2023  润新知