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;
}