给定 n 个区间 [ai,bi] 和 n 个整数 ci。
你需要构造一个整数集合 Z,使得 ∀i∈[1,n],Z 中满足 ai≤x≤bi 的整数 x 不少于 ci 个。
求这样的整数集合 Z 最少包含多少个数。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含三个整数 ai,bi,ci。
输出格式
输出一个整数表示结果。
数据范围
1≤n≤500001
0≤ai,bi≤50000
0≤ci≤bi−ai+1
输入样例:
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
输出样例:
6
解析:
差分约束系统 是一种特殊的 n 元一次不等式组,它包含 n 个变量 x1,x2,……,xn 以及 m 个约束条件,每个约束条件是由两个其中的变量做差构成的,形如 xi-xj<=ck,其中 1 <= i, j <= n, i != j, 1 <= k <= m 并且 ck 是常数(可以是非负数,也可以是负数)。我们要解决的问题是:求一组解 x1=a1,x2=a2,……,xn=an,使得所有的约束条件得到满足,否则判断出无解。
差分约束系统中的每个约束条件 xi-xj<= ck 都可以变形成 xi <= xj+ck,这与单源最短路中的三角形不等式 dist[y]<= dist[x]+z 非常相似。因此,我们可以把每个变量 xi 看做图中的一个结点,对于每个约束条件 xi-xj<= ck,从结点 j 向结点 i 连一条长度为 ck 的有向边。
注意到,如果 {a1,a2,……,an} 是该差分约束系统的一组解,那么对于任意的常数 d,{a1+d,a2+d,……,an+d\} 显然也是该差分约束系统的一组解,因为这样做差后 d 刚好被消掉。
对于条件 xi<=xj+ck,我们可以通过上述方法建图求最短路,无负环则有解;而对于 xi>=xj+ck,我们可以转换为 xj-xi<=-ck 然后求最短路,也可以直接求最长路(正环有解)。
由此可以知道:差分约束算法参考自最短路算法
差分约束最难的地方是找不等式关系。
本题可以利用前缀和的思想。因此我们不希望0号点被用到,所以我们可以给每个数+1,这样范围就成1~50001。
S[i]表示1~i中被选出的数的个数,显然S[5001]的最小值为答案。
s[i]需要满足:
1)s[i]>=s[i-1] ,1<=i<=5001
2)s[i]-s[i-1] <=1 ,等价于: s[i-1]>=s[i]-1
3)s[b]-s[a-1]>=c
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
#include<sstream>
#include<deque>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N = 5e4 + 5, M = N*3 + 5;
int n;
int h[N], e[M], w[M], ne[M], idx;
int q[N], dist[N], vis[N];
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void spfa() {
//cout << "KKKKKKKKKKKKKKKKKKKKKKKKKKKK" << endl;
memset(dist, -0x3f, sizeof dist);
int hh = 0, tt = 1;
q[0] = 0;
dist[0] = 0;
vis[0] = 1;
while (hh != tt) {
int t = q[hh++];
if (hh == N)hh = 0;
vis[t] = 0;
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
if (dist[j] < dist[t] + w[i]) {
dist[j] = dist[t] + w[i];
if (!vis[j]) {
vis[j] = 1;
q[tt++] = j;
if (tt == N)tt = 0;
}
}
}
}
}
int main() {
cin >> n;
memset(h, -1, sizeof h);
for (int i = 1; i <= 50001; i++) {
add(i - 1, i, 0);
add(i, i - 1, -1);
}
for (int i = 1,a,b,c; i <= n; i++) {
scanf("%d%d%d", &a, &b, &c);
a++, b++;
add(a-1, b, c);
}
spfa();
cout << dist[50001] << endl;
return 0;
}