https://vjudge.net/contest/375481#problem/I
这道题是一个带权的并查集(需要复习)
总体思路:1.由于无法直接通过两个点之间距离再次出现来判断v是否相等 只能借助于并查集间的联代关系 创造一个中间节点 即 祖宗节点;
2.先对并查集进行初始化,同时对sum也进行初始化(sum代表的是 点i到根节点的距离)
3.特判 1如果两个点不是一个集合的点 需要将两个点连接 注意:连接的时候会造成sum【x】(在此处x是a点的祖宗节点)的改变 因为x指向了y点 x到根节点的距离需要重新定义
同时这是属于区间的更新 区间的更新有一个性质 半开区间性质 (a,b]+(b,c]=(a,c] 因此我们去点要取到开区间上那个点 即做a--的操作
4.上次sum【x】的更新也会影响到它的子节点的距离 ,它的子节点的距离在find中有 即sum【x】+=sum【f】,这个会在 x下次出现的时候自动更新 (在sum【x】更新后的事) 存疑
5.特判2 如果两个点是一个集合 ,直接进行减法 ,判断是否等于v,否,则错误,ans++。注意这里a是比b远的,所以用a-b ;
#include<iostream>
using namespace std;
const int N=5e5+10;
int p[N],sum[N];
int find(int x)
{
if(p[x] != x)
{
int f = p[x];
p[x] = find(p[x]);
sum[x] += sum[f];
}
return p[x];
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
int ans=0;
for(int i=0;i<=n;i++)
{
p[i]=i;
sum[i]=0;
}
int a,b,v;
while(m--)
{
scanf("%d%d%d", &a, &b, &v);
a-=1;
int x = find(a);
int y = find(b);
if(x != y)
{
p[x] = y;
sum[x] = sum[b] - sum[a] + v;
}
else
{
if(sum[a] - sum[b] != v) ans++;
}
}
printf("%d\n", ans);
}
return 0;
}