差分约束存在性问题很简单,spfa判环即可。
难点在于求某个变量的最大值,或者某两个变量差的最大/最小值。
求某个变量的最大值我们可以转化为后者。即令x0=0 , xi-x0<=0 / xi-x0>=0;
先说下结论:
求变量差最大值,变成小于等于号,建图求最短路。
求变量差最小值,变成大于等于号,建图求最长路。
当然你可以强行给变量差加个符号,使得一定取最大/最小,使用最短路/最长路。(但一般不强行变,因为要求单源多终点时,必须保证超级源点到每个点都可达,很多情况下,强行变要连反边,使得超级源点不可达每个点。进而d[x]无意义)
给出若干个不等式,求 xi - xj 这个变量的最大值。
其中有一个不等式:xi - xj <= c; (这样能保证xj - > xi 可达,否则无意义,即可任意取值)
建出图后。
把所有不等式变化为: y <=x + c
满足最短路里的三角不等式: d[y] <= d[x] + w
建图求出 xj - > xi 的最短路,即是所有约束xj - > xi 条件中的最小值,即能取到的最大值。
(比如还有一些限制条件,转化为了: xi - xj <= d, (d<=c), 那么最短路变成了d,即最大只能取到d,再往上取就会不满足约束条件)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 2e5+7;
int head[M],cnt=1;
void init(){cnt=1,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
int d[M],vs[M];
int n,m;
void spfa()
{
memset(d,0x3f,sizeof(d));
queue<int>q;
q.push(50001);
d[50001]=0;vs[50001]=1;
while(q.size())
{
int x=q.front();q.pop();
vs[x]=0;
for(int i=head[x];i;i=ee[i].nxt)
{
int y=ee[i].to,w=ee[i].w;
// cout<<x<<" "<<y<<" "<<w<<" "<<d[x]<<" "<<d[y]<<endl;
if(d[y]>d[x]+w)
{
d[y]=d[x]+w;
if(!vs[y])q.push(y),vs[y]=1;
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
int x,y,w;
cin>>x>>y>>w;
y++;
//y-x>=c x<=-c+y
add(y,x,-w);
}
// d[i]-d[i-1]>=0 -> d[i-1]<=d[i]+0
// d[i]-d[i-1]<=1 -> d[i]<=d[i-1]+1
// d[ed]-d[0]>=0 -> d[0]<=d[ed] 求出 d[0]-d[ed] 即 -d[ed] 的最大值
for(int i=1;i<=50001;i++)add(i,0,0),add(i-1,i,1),add(i,i-1,0);//超级原点,目的是求每个点的最小值
spfa();//一定有解 ,即不存在负环
cout<<-d[0]<<endl;
return 0;
}