题目传送门

//求解本题需要弄清楚冲突发生的条件,很容易看出此题为种类并查集的变种,题上提到了距离,自然想到是带权值的并查集,关键是这个权值怎么办。
//菜鸟参考网上各位大牛的解法终于懂了这道题的前因后果。有必要将解题过程中的心得体会记录下来。
//(1)弄清题意,找出出现冲突的位置,判断冲突很简单就是当两个人在同一行坐,同时他们到根节点的距离差值正好是他们之间的差值,此时就出现了冲突了。(本质就是两个人到了同样的位置)
//(2)关键有两个地方,这也是并查集题目的难点,就是压缩集合,和求节点到根的距离。这里压缩集合就很简单了,一个通用的递归。求到根的距离:   dist[a]+= dist[tem]; 
dist[rb]=dist[a]+x-dist[b];
//注意这两行代码,这是核心代码,首先第一行是求出节点a到根的距离。第二行代码使用的是数学中向量计算的原理如图
![图片](https://img-blog.csdn.net/20160115202251039)

//Created Author: just_sort
//Created Time : 2016/1/15 19:59
//File Name : Zjtu Stadium
#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
using namespace std;
const int maxn=50010;
int fa[maxn],dis[maxn];

void init()
{
    for(int i=0;i<maxn;i++)
    {
        fa[i]=i;
        dis[i]=0;
    }
}
int Find(int x)
{
    if(x==fa[x])return x;
    int fx=fa[x];
    fa[x]=Find(fa[x]);
    dis[x]+=dis[fx];//节点x到根的距离
    return fa[x];
}
void union_set(int u,int v,int x)
{
    int fx = Find(u);
    int fy = Find(v);
    fa[fy]=fx;
    dis[fy]=dis[u]-dis[v]+x;//数学中距离的计算(向量法)
}
int main()
{
    int n,m,ans;
    int u,v,w;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        ans=0;
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            if(Find(u)!=Find(v))union_set(u,v,w);
            else if(dis[u]+w!=dis[v])ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}