用并查集维护类似前缀和的东西,用v[x]表示从x到连通块根的价值
如果两个点已经在一个集合里说明它们之间的价值已经求出来了,比如点对(x,y)已经在一个集合里,只需要判断v[y]-v[x]?=z;若不在一个集合里,将x,y合并,合并过程如下:
1.设p=find(x),q=find(y);
2.v[y]=s[y]-s[q],v[x]=s[x]-s[p];z=s[y]-s[x];
3.得出v[p]=v[y]-v[x]-z;
不断用并查集维护v[]即可
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1005;
int fa[N],v[N];
int n,m,T;
bool flag;
int find(int x)
{
if(fa[x]==x) return x;
int q=find(fa[x]);
v[x]+=v[fa[x]];
fa[x]=q;
return fa[x];
}
void add(int x,int y,int z)
{
int p=find(x),q=find(y);
if(p!=q)//合并
{
fa[p]=q;
v[p]=v[y]-v[x]-z;
}
else if(v[y]-v[x]!=z) flag=1;//如果已经在一个连通块里,判断
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(v,0,sizeof(v));
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++) fa[i]=i;
flag=0;
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(!flag) add(x-1,y,z);
}
if(flag) printf("false\n");
else printf("true\n");
}
}