[Disjoint Set] HDU 3038 How Many Answers Are Wrong

HDU 3038 How Many Answers Are Wrong

带权并查集:路径压缩真巧妙

#include"stdio.h"
#include"string.h"
#include"math.h"
#include<algorithm>
#include<vector>
using namespace std;
const int MAX_N=200005;
int N,M;
int fa[MAX_N];
int w[MAX_N];

void makeSet(){
    for (int i = 0; i <= N; i++)
    {
        fa[i]=i;
        w[i]=0;
        // why?初始化:每个点到自己的距离为0
    }
}
int Find(int x){// Find不改变秩,但是带权并查集的权指着Find更新,好比fa[i]和Find(i)之间的关系
    if(fa[x]==x) return x;
    else{
        // why!递归时各层Find返回时的值都是根节点,因此必须保存各层递归之前的父节点
        int tmp = fa[x];
        fa[x] = Find(fa[x]);
        w[x] += w[tmp];
        // after recursively Find
        return fa[x];
    }
}
bool Union(int a,int b,int s){
    int ra = Find(a);
    int rb = Find(b);
    if(ra==rb){
        if((w[a]-w[b])!=s) return false;
        else return true;
    } 
    else {
        if(ra > rb){
            fa[rb] = ra;
            w[rb] = w[a] - s - w[b];
        }else{
            fa[ra] = rb;
            w[ra] = w[b] + s - w[a];
        }
    }
    return true;
}
int main(){
    while(scanf("%d %d",&N,&M)!=EOF){
        makeSet();
        int cnt=0;
        for(int m=0;m<M;m++){
            int A,B,S;
            scanf("%d %d %d",&A,&B,&S);
            if(!Union(A-1,B,S)) cnt++;// left open right close
        }
        printf("%d
", cnt);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/chengyh23/p/14585384.html