• 并查集


    一.普通并查集

    int find(int x){
        if(f[x]==x)return x;
        return f[x]=find(f[x]);
    }

    二.带权并查集

    int find(int x){
        if(f[x]==x)return x;
        find(f[x]);
        work();//用儿子与爷爷关系和(儿子与父亲关系和父亲与爷爷关系)的关联,更新权值为儿子与爷爷关系
        return f[x]=f[f[x]];
    }

    http://cogs.pro/cogs/problem/problem.php?pid=298

    /******************************************************************
    
                                带权并查集
                                
    Part I - 权值(relation)的确定。
            我们可以用动物之间“相对”的关系来确定一个并查集。
            0 - 这个节点与它的父节点是同类
            1 - 这个节点被它的父节点吃
            2 - 这个节点吃它的父节点。
            第一个数字(下文中,设为d)指定了后面两种动物的关系:
            1 - X与Y同类
            2 - X吃Y
    
    
    Part II - 路径压缩,以及节点间关系确定
        (1)路径压缩节点时的算法
            通过穷举我们可以发现
            f[now]=f[f[now]]
            relation[now]=(relation[now]+relation[f[now]]) % 3
            推理过程 
            父亲是自己 relation[now]=0;0+0=0; 
            父亲不是自己 
    爷爷(可能还是父亲)和 父亲和儿子   儿子与爷爷
            0          0      (i + j)%3 = 0
            0          1      (i + j)%3 = 1
            0          2      (i + j)%3 = 2
            1          0      (i + j)%3 = 1
            1          1      (i + j)%3 = 2
            1          2      (i + j)%3 = 0
            2          0      (i + j)%3 = 2
            2          1      (i + j)%3 = 0
            2          2      (i + j)%3 = 1
            注:要先更新父亲再更新儿子,可以直接跳到根节点
        (2)集合间关系的确定
            relation[find(y)]=(relation[x]-relation[y]+(d-1)+3) % 3;
            证明:
                y与find(x)的关系为w=(relation[x]+(d-1))%3(其中(d-1)为y与x的关系,可以把x当作y的父节点推出来) 
                find(y)与find(x)的关系要用路径压缩算法反着推出来 relation[find(y)]=(w-relation[y]+3)%3 
                
    Part III - 判断
            如果 find(x)==find(y)代表以前确立了关系,(d-1)表示y与x的关系
            relation[y]是y与根关系,(3-relation[x])%3是根与x关系
            如果(relation[y]-relation[x]+3)%3!=d-1则为假话 
    
    ******************************************************************/
    #include<cstdio>
    #define maxn 50000
    int f[maxn],relation[maxn];
    int find(int x){
        if(f[x]==x)return x;
        find(f[x]);
        relation[x]+=relation[f[x]];relation[x]%=3;
        return f[x]=f[f[x]];
    }
    int mo(int x){
        return x>=0?x%3:(x%3)+3;
    }
    int main(){
        freopen("eat.in","r",stdin);
        freopen("eat.out","w",stdout);
        int n,ans=0,k,d,x,y,a,b;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            f[i]=i;
        }
        for(int i=0;i<k;i++){
            scanf("%d%d%d",&d,&x,&y);d--;
            if(x>n||y>n){
                ans++;
                continue;
            }
            a=find(x),b=find(y);
            if(a==b){
                if(mo(relation[y]-relation[x])!=d)ans++;
            }
            else{
                relation[b]=mo(relation[x]-relation[y]+d);
                f[b]=a;
            }
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    正则表达式分类
    数据思维二三事
    关于编程语言的一些趣史
    重构后端模板文件的一种实践
    为什么程序员需要知道互联网行业发展史
    探秘JS的异步单线程
    Nerd的畅销产品
    Nerd的套现ATM机
    网络传输与加密 (2)
    网络传输与加密
  • 原文地址:https://www.cnblogs.com/bennettz/p/7356959.html
Copyright © 2020-2023  润新知