题意是给你a,b,c说明a在b后面c个单位(c<0就是在左边),每个位置只能有一个数,一共有n个位置,告诉你m个关系,问是否符合条件
我们可以设置d[x]表示x到它的最早的父节点的距离,然后如果两个数父节点一样,那么c!=d[a]-d[b]时就说明不符合条件
那么对于并查集的合并是怎么操作的呢?
如图,如果输入的是b,y,s说明b在y的右边s距离,我们只需要把a放到y右边(s-d[b])距离即可
需要注意的是,在更新边权的时候,要等它的父节点更新边权完成后再加上它父节点的边权
查看代码
// Problem: H. The Third Letter
// Contest: Codeforces - Codeforces Round 886 (Div. 4)
// URL: https://codeforces.com/problemset/problem/1850/H
// Memory Limit: 256 MB
// Time Limit: 2000 ms
#pragma GCC optimize(2)
#include<iostream>
#define int long long
using namespace std;
int f[200005],d[200005];
int ff(int x)
{
if(x==f[x])return x;
int tmp=f[x],cc=ff(f[x]);
d[x]+=d[tmp];//等父节点更新完边权后再更新该节点边权
f[x]=cc;
return cc;
}
void solve()
{
int n,m;
cin>>n>>m;
bool s=1;
for(int i=1;i<=n;i++)f[i]=i,d[i]=0;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
int a=ff(x),b=ff(y);
if(a!=b)
{
d[a]=z-d[x];
f[a]=y;
}
else
{
if(z!=d[x]-d[y])
{
s=0;
}
}
}
if(!s)
{
cout<<"NO\n";
}
else cout<<"YES\n";
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--)solve();
return 0;
}