小 K 的农场
题目描述
小 K 在 MC 里面建立很多很多的农场,总共 n n n 个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共 m m m 个),以下列三种形式描述:
- 农场 a a a 比农场 b b b 至少多种植了 c c c 个单位的作物;
- 农场 a a a 比农场 b b b 至多多种植了 c c c 个单位的作物;
- 农场 a a a 与农场 b b b 种植的作物数一样多。
但是,由于小 K 的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。
输入格式
第一行包括两个整数 n n n 和 m m m,分别表示农场数目和小 K 记忆中的信息数目。
接下来 m m m 行:
- 如果每行的第一个数是 1 1 1,接下来有三个整数 a , b , c a,b,c a,b,c,表示农场 a a a 比农场 b b b 至少多种植了 c c c 个单位的作物;
- 如果每行的第一个数是 2 2 2,接下来有三个整数 a , b , c a,b,c a,b,c,表示农场 a a a 比农场 b b b 至多多种植了 c c c 个单位的作物;
- 如果每行的第一个数是 3 3 3,接下来有两个整数 a , b a,b a,b,表示农场 a a a 种植的的数量和 b b b 一样多。
输出格式
如果存在某种情况与小 K 的记忆吻合,输出 Yes
,否则输出 No
。
样例 #1
样例输入 #1
3 3
3 1 2
1 1 3 1
2 2 3 2
样例输出 #1
Yes
提示
对于 100 % 100\% 100% 的数据,保证 1 ≤ n , m , a , b , c ≤ 5 × 1 0 3 1 \le n,m,a,b,c \le 5 \times 10^3 1≤n,m,a,b,c≤5×103。
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define il inline
#define re register
#define FOR(i,n,s) for(int i=(s);i<=(n);i++)
const int MAXN=1e8+5;
vector<pii> edges[MAXN];
int dis[MAXN];
int n,m,s;
int cnt[MAXN];
bool inQueue[MAXN];
queue<int> q;
//SPFA
il void add(int u,int v,int w)
{
edges[u].emplace_back(v,w);
}
il bool SPFA(int s)
{
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
q.push(s);
inQueue[s]=true;
while(!q.empty())
{
int x=q.front();q.pop();
inQueue[x]=false;
for(auto edge:edges[x])
{
if(dis[edge.first]<=dis[x]+edge.second) continue;
dis[edge.first]=dis[x]+edge.second;
if(!inQueue[edge.first])
{
q.push(edge.first);
inQueue[edge.first]=true;
cnt[edge.first]++;
if(cnt[edge.first]>=n+1) return false;
}
}
}
return true;
}
//标准的SPFA模板
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v,w,opt;
cin>>opt>>u>>v;
if(opt<3) cin>>w;
if(opt==1) add(u,v,-w);
if(opt==2) add(v,u,w);
if(opt==3) {add(u,v,0);add(v,u,0);}
}//建图
for(int i=0;i<=n;i++) add(0,i,0);//建立超级源点
if(!SPFA(0)) cout<<"No";
else cout<<"Yes";
return 0;
}
PS:
题目其中 m 条信息有如下三种形式:
1.
a
i
−
a
j
>
=
c
1.a_i-a_j>=c
1.ai−aj>=c
2.
a
i
−
a
j
<
=
c
2.a_i-a_j<=c
2.ai−aj<=c
3.
a
i
=
a
j
3.a_i=a_j
3.ai=aj
我们可以把这三种形式转化为:
1.
a
j
<
=
a
i
−
c
1.a_j<=a_i-c
1.aj<=ai−c
2.
a
i
<
=
a
j
+
c
2.a_i<=a_j+c
2.ai<=aj+c
3.
a
i
−
a
j
=
0
3.a_i-a_j=0
3.ai−aj=0
看到这三个不等式我们很容易就会想到这道题用查分约束解决
根据这三个不等式,我们可以依次建边:
1.
(
j
,
i
,
−
c
)
1.(j,i,-c)
1.(j,i,−c)
2.
(
i
,
j
,
c
)
2.(i,j,c)
2.(i,j,c)
3.
(
i
,
j
,
0
)
(
j
,
i
,
0
)
3.(i,j,0)(j,i,0)
3.(i,j,0)(j,i,0)
然后我们跑一遍SPFA即可(更多关于模板的细节可看前几篇题解)