The Third Letter带权并查集

发布时间 2023-07-27 09:42:51作者: qbning

Problem - 1850H - Codeforces

题意是给你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;
}