传送门

n n n个人排队

x x x个相互喜欢的关系,表示 d i s [ u ] − d i s [ v ] < = w dis[u]-dis[v]<=w dis[u]dis[v]<=w

y y y个相互厌恶的关系,表示 d i s [ u ] − d i s [ v ] > = w dis[u]-dis[v]>=w dis[u]dis[v]>=w


d i s [ u ] < = d i s [ v ] + w dis[u]<=dis[v]+w dis[u]<=dis[v]+w

那么 v v v u u u连一条权值 w w w的边

d i s [ v ] < = d i s [ u ] − w dis[v]<=dis[u]-w dis[v]<=dis[u]w

那么 u u u v v v连一条边权 − w -w w的边

而且需要满足 d i s [ i ] > = d i s [ i − 1 ] dis[i]>=dis[i-1] dis[i]>=dis[i1]

那么 i i i i − 1 i-1 i1连一条边权 0 0 0的边

然后跑最短路,即可

若最后 d i s [ n ] dis[n] dis[n]仍然是 i n f inf inf,说明没有限制条件,可以无限远

若有负环存在,会一直在环里减小,其实是无解的

#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9;
const int maxn = 2e6+10;
int t,n,q,qq;
struct edge{
	int to,nxt,w;
}d[maxn]; int head[maxn],cnt=1;
int dis[maxn],vis[maxn],shu[maxn];
void add(int u,int v,int w){
	d[++cnt] = (edge){v,head[u],w},head[u] = cnt;
}
int spfa(int s)
{
	for(int i=1;i<=n;i++)	dis[i] = inf, vis[i] = shu[i] = 0;
	queue<int>q; dis[s] = 0; q.push( s );
	while( !q.empty() )
	{
		int u = q.front(); q.pop();
		vis[u] = 0;
		for(int i=head[u];i;i=d[i].nxt )
		{
			int v = d[i].to;
			if( dis[v]>dis[u]+d[i].w )
			{
				dis[v] = dis[u]+d[i].w;
				if( !vis[v] )
				{
					vis[v] = 1, q.push( v );
					if( ++shu[v]==n )	return -1;
				}
			}
		}
	}
	if( dis[n]==inf )	return -2;
	return dis[n];
}
int main()
{
	cin >> t;
	while( t-- )
	{
		cin >> n >> q >> qq;
		for(int i=2;i<=n;i++)	add(i,i-1,0);
		for(int i=1;i<=q;i++)
		{
			int l,r,w; scanf("%d%d%d",&l,&r,&w);
			add(l,r,w);
		}
		for(int i=1;i<=qq;i++)
		{
			int l,r,w; scanf("%d%d%d",&l,&r,&w);
			add(r,l,-w);
		}
		cout << spfa(1) << endl;
		cnt = 1;
		for(int i=1;i<=n;i++)	head[i] = 0;
	}
}