实际上运用带权并查集的模板可以很好地解决这个问题。。
注意并查集应从0-n初始化,我们把第i月和第0个月的差值设为num[i],并且初始化为0。find函数进行并查集寻找父亲的操作,只不过在这个过程中,要更新num[x]。若二者有父亲结点不同,就更新父亲结点,并更新num数组(例如我是把f2接到f1上,假设f2比f1大z,那么可以得到更新后num[y]+num[f2]=num[x]+z,移项可表示num[f2])。如果二者父亲相同 就需要判断账目是否为真了,由于我假定是后面的月份和前面的月份作差,就只需要比较num[y]-num[x]!=z即可,注意用标记来记录真假情况。带权并查集比较绕,要明白自己写的x和y是什么含义、谁是父亲,这样能作差得到正确的结果。我一开始把判断是否为相同父亲的情况写到一个合并函数里,结果就找完父亲后又判断了一遍。。两者应当是if-else的关系,以后别搞混了。。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=110;
const int maxm=1010;
int n,m,w;
int fa[maxn],num[maxn];
int find(int x)
{
if(fa[x]==x) return x;
int t=fa[x];
fa[x]=find(fa[x]);
num[x]+=num[t];
return fa[x];
}
int main()
{
cin>>w;
while(w--)
{
cin>>n>>m;
for(int i=0;i<=n;i++)
{
fa[i]=i;
num[i]=0;
}
bool bb=true;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
x--;
int f1=find(x),f2=find(y);
if(f1!=f2)
{
fa[f2]=f1;
num[f2]=num[x]-num[y]+z;
}
else if(num[y]-num[x]!=z)
{
bb=false;
}
// cout<<num[y]<<' '<<num[x]<<endl;
}
if(bb==true) cout<<"true"<<endl;
else cout<<"false"<<endl;
}
return 0;
}