题目大意
小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述:
- 农场a比农场b至少多种植了c个单位的作物,
- 农场a比农场b至多多种植了c个单位的作物,
- 农场a与农场b种植的作物数一样多。
但是,由于小K的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。
差分约束
要处理一组类似$x_{i1}+k_igeq x_{i2}$的形式的偏序关系,我们发现图上每条边e连接的两个结点的单源最短路径长度都满足u[e]+w[e]>=v[e](u可能在v的最短路径上,也可能不在)。所以我们将图上的结点$x_{i1}, x_{i2}$连一条长度为$k_i$的边,将原点与所有边相连,跑一下最短路,那么每个结点的dist就是其所对应$x$值的一个解。
无解当且仅当图中有负环,判断负环的方法可以为:在SPFA时,判断每个结点的最短路径所经过的结点的数量是否超过TotNode,超过了则说明有负环。
题解说明
使用STL里的queue维护Node*,在BZOJ上可以AC,在洛谷上由于评测机64位指针8子节导致RE;queue改为维护int原先RE变为TLE,开O2后AC,不开O2即使手写queue也没有卵用。据说有用Dfs实现的SPFA,但是我不会。
// luogu-judger-enable-o2
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int MAX_NODE = 10010, MAX_EDGE = MAX_NODE * 3, INF = 0x3f3f3f3f;
struct Node;
struct Edge;
struct Node
{
Edge *Head;
int Dist, FromEdgeCnt;
bool Inq;
}_nodes[MAX_NODE];
int _vCount;
struct Edge
{
Node *To;
Edge *Next;
int Weight;
}_edges[MAX_EDGE];
int _eCount;
void AddEdge(int uId, int vId, int w)
{
Node *u = _nodes + uId, *v = _nodes + vId;
Edge *e = _edges + ++_eCount;
e->Weight = w;
e->To = v;
e->Next = u->Head;
u->Head = e;
}
bool SPFA(Node *start)
{
for (int i = 1; i <= _vCount; i++)
_nodes[i].Dist = INF;
start->Dist = 0;
start->FromEdgeCnt = 0;
start->Inq = true;
static queue<int> q;
q.push(start - _nodes);
while (!q.empty())
{
int curId = q.front();
q.pop();
Node *cur = _nodes + curId;
cur->Inq = false;
if (cur->FromEdgeCnt > _vCount)
return false;
for (Edge *e = cur->Head; e; e = e->Next)
{
if (cur->Dist + e->Weight < e->To->Dist)
{
e->To->Dist = cur->Dist + e->Weight;
e->To->FromEdgeCnt = cur->FromEdgeCnt + 1;
if (!e->To->Inq)
{
e->To->Inq = true;
q.push(e->To - _nodes);
}
}
}
}
return true;
}
int main()
{
int qCnt;
_eCount = 0;
scanf("%d%d", &_vCount, &qCnt);
_vCount++;
for (int i = 1; i <= qCnt; i++)
{
int op, a, b, c;
scanf("%d", &op);
switch (op)
{
case 1:
scanf("%d%d%d", &a, &b, &c);
AddEdge(a, b, -c);
break;
case 2:
scanf("%d%d%d", &a, &b, &c);
AddEdge(b, a, c);
break;
case 3:
scanf("%d%d", &a, &b);
AddEdge(a, b, 0);
AddEdge(b, a, 0);
break;
}
}
for (int i = 1; i <= _vCount - 1; i++)
AddEdge(_vCount, i, 0);
if (SPFA(_nodes + _vCount))
printf("Yes
");
else
printf("No
");
return 0;
}