[HNOI2005]狡猾的商人 带权并查集

给定m个区间和,问是否有矛盾

复习一下,带权并查集保存着这个元素与祖先的关系

在合并的过程中就像向量合并一样,可以画出x->fa[x],y->fa[y],x->y这样的图方便理解

这篇文章解释得很清楚NOIAu

//#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<stack>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mem(a) memset(a,0,sizeof a)
#define FOR(a) for(int i=1;i<=a;i++)
 
const int maxn=1e2+7;
 
int fa[maxn],v[maxn],flag,t;
 
int find(int x){
    if(fa[x]==x)return x;
    t=find(fa[x]);
    v[x]+=v[fa[x]];
    fa[x]=t;
    return fa[x];
}
 
void work(int x,int y,int w){
    int p=find(x),q=find(y);
    if(p!=q){
        fa[p]=q;
        v[p]=v[y]-v[x]-w;
    }else if(v[y]-v[x]!=w)flag=1;
}
 
int main(){
    int w,n,m;scanf("%d",&w);
    while(w--){
        memset(v,0,sizeof v);
        flag=0;
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n;i++)fa[i]=i;
        for(int i=1;i<=m;i++){
            int x,y,z;scanf("%d%d%d",&x,&y,&z);
            if(!flag)work(x-1,y,z);
        }
        if(flag)printf("false
");else printf("true
");
    }
}



原文地址:https://www.cnblogs.com/Drenight/p/8611226.html