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